pub static mut M_ADDING_PLOT:i32 = -1; //Plot to be added
pub static mut M_CANCEL_CLICK:bool = false; //Exit click event
pub static mut M_CANVAS_WIDTH:f32 = 900.0; //Width of Canvas
pub static mut M_CANVAS_HEIGHT:f32 = 800.0; //Height of Canvas
pub static mut M_DRAG_BEGIN_POINT:FCPoint = FCPoint{x:0.0, y:0.0}; //Starting drag coordinate
pub static mut M_DRAG_BEGIN_RECT:FCRect = FCRect{left:0.0, top:0.0, right:0.0, bottom:0.0}; //Start drag area
pub static mut M_DRAGGING_VIEW:i32 = -1; //View being dragged
pub static mut M_FOCUSED_VIEW:i32 = -1; //View being focused
pub static mut M_FIRST_TOUCH:bool = false; //Is it the first touch
pub static mut M_IS_MOBILE:bool = false; //Mobile or not
pub static mut M_IS_DOUBLECLICK:bool = false; //Double click or not
pub static mut M_LASTCLICKTIME:i64 = 0; //Last click time
pub static mut M_NOW_ID:i32 = 0; //Current static id
pub static mut M_RATIO:f32 = 1.0; //Interface scaling ratio
pub static mut M_RESIZE_COLUMN_STATE:i32 = 0; //The state of dragging column headers
pub static mut M_RESIZE_COLUMN_BEGINWIDTH:f32 = 0.0; //Start drag width of column header
pub static mut M_RESIZE_COLUMN_INDEX:i32 = -1; //Start drag index of column header
pub static mut M_SECOND_TOUCH:bool = false; //Is it the second touch
pub static mut M_START_POINT:FCPoint = FCPoint{x:0.0, y:0.0}; //Coordinates to start clicking on
pub static mut M_TOUCH_DOWN_VIEW:i32 = -1; //View being pressed
pub static mut M_TOUCH_MOVE_VIEW:i32 = -1; //View begin touch moved
pub static mut M_TOUCH_DOWN_POINT:FCPoint = FCPoint{x:0.0, y:0.0}; //Coordinates to touch down
pub static mut M_TOUCH_POINT:FCPoint =FCPoint{x:0.0, y:0.0}; //Coordinates to touch
pub static mut M_TOUCH_FIRST_POINT:FCPoint = FCPoint{x:0.0, y:0.0}; //Coordinates of the first touch
pub static mut M_TOUCH_SECOND_POINT:FCPoint = FCPoint{x:0.0, y:0.0}; //Coordinates for the second touch

/*
* Coordinate structure
*/
#[derive(Clone)]
pub struct FCPoint{
	x: f32, //Abscissa
	y: f32 //Ordinate
}

/*
* Size structure
*/
#[derive(Clone)]
pub struct FCSize{
	cx: f32, //Width
	cy: f32 //Height
}

/*
* Rectangular structure
*/
#[derive(Clone)]
pub struct FCRect{
	left: f32, //Left
	top: f32, //Top
	right: f32, //Right
	bottom: f32 //Bottom
}

/*
* Padding structure
*/
#[derive(Clone)]
pub struct FCPadding{
	left: f32, //Left
	top: f32, //Top
	right: f32, //Right
	bottom: f32 //Bottom
}

/*
* Drawing Structure
*/
#[derive(Clone)]
pub struct FCPaint{
	default_ui_style:String, //Default style
	move_to:bool,
	offset_x:f32, //Offset X
	offset_y:f32, //Offset Y
	scale_factor_x:f32, //Horizontal scaling ratio
	scale_factor_y:f32 //Vertical scaling ratio
}

impl FCPaint{
	fn new()->Self{
		Self{
			default_ui_style:String::from("dark"),
			move_to:false, 
			offset_x:0.0, 
			offset_y:0.0, 
			scale_factor_x:1.0, 
			scale_factor_y:1.0
		}
	}
	/*
	* Add line
	* context:Drawing context
	* x1:X1
	* y1:Y1
	* x2:X2
	* y2:Y1
	*/
	fn add_line(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, x1:f32, y1:f32, x2:f32, y2:f32){
		if !self.move_to {
			self.move_to = true;
			context.move_to(((x1 + self.offset_x) * self.scale_factor_x) as f64, ((y1 + self.offset_y) * self.scale_factor_y) as f64);
		}
		context.line_to(((x2 + self.offset_x) * self.scale_factor_x) as f64, ((y2 + self.offset_y) * self.scale_factor_y) as f64);
	}
	/*
	* Begin path
	* context:Drawing context
	*/
	fn begin_path(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>){
		context.begin_path();
	}
	/*
	* Begin paint
	* context:Drawing context
	*/
	fn begin_paint(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>){
		self.move_to = false;
		self.offset_x = 0.0;
		self.offset_y = 0.0;
	}
	/*
	* Close figure
	* context:Drawing context
	*/
	fn close_figure(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>){
		context.close_path();
	}
	/*
	* Close path
	* context:Drawing context
	*/
	fn close_path(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>){
		self.move_to = false;
	}
	/*
	* Draw line
	* context:Drawing context
	* color:Color
	* width:width
	* style:Style
	* x1:X1
	* y1:Y1
	* x2:X2
	* y2:Y1
	*/
	fn draw_line(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, color:String, width:f32, style:Vec<f32>, x1:f32, y1:f32, x2:f32, y2:f32){
		if color != "none"{
			let mut l_width = self.scale_factor_x.min(self.scale_factor_y) * width;
			context.begin_path();
			if l_width < 1.0{
				l_width = 1.0;
			}
			context.set_line_width(l_width as f64);
			let c = JsValue::from(String::from(color));
			context.set_stroke_style(&c);  
		    
			context.move_to(((x1 + self.offset_x) * self.scale_factor_x) as f64, ((y1 + self.offset_y) * self.scale_factor_y) as f64);
			context.line_to(((x2 + self.offset_x) * self.scale_factor_x) as f64, ((y2 + self.offset_y) * self.scale_factor_y) as f64);
			context.stroke();
		}
	}
	/*
	* Draw path
	* context:Drawing context
	* color:Color
	* width:width
	* style:Style
	*/
	fn draw_path(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, color:String, width:f32, style:Vec<f32>){
		if color != "none"{
			let mut l_width = self.scale_factor_x.min(self.scale_factor_y) * width;
			if l_width < 1.0{
				l_width = 1.0;
			}
			context.set_line_width(l_width as f64);
			let c = JsValue::from(String::from(color));
			context.set_stroke_style(&c);  
			context.stroke();
		}
	}
	/*
	* Draw rect
	* context:Drawing context
	* color:Color
	* width:width
	* style:Style
	* left:Left
	* top:Top
	* right:Right
	* bottom:Bottom
	*/
	fn draw_rect(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, color:String, width:f32, style:Vec<f32>, left:f32, top:f32, right:f32, bottom:f32){
		if color != "none"{
			let mut l_width = self.scale_factor_x.min(self.scale_factor_y) * width;
			let w = right - left;
			let h = bottom - top;
			context.begin_path();
			if l_width < 1.0{
				l_width = 1.0;
			}
			context.set_line_width(l_width as f64);
			let c = JsValue::from(String::from(color));
			context.set_stroke_style(&c);  
			context.stroke_rect(((left + self.offset_x) * self.scale_factor_x) as f64, ((top + self.offset_y) * self.scale_factor_y) as f64, (w * self.scale_factor_x) as f64, (h * self.scale_factor_y) as f64);
		}
	}
	/*
	* Draw rect
	* context:Drawing context
	* color:Color
	* width:width
	* style:Style
	* left:Left
	* top:Top
	* right:Right
	* bottom:Bottom
	* corner_radius Corner radius
	*/
	fn draw_round_rect(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, color:String, width:f32, style:Vec<f32>, left:f32, top:f32, right:f32, bottom:f32, corner_radius:f32){
		if color != "none"{
			let mut l_width = self.scale_factor_x.min(self.scale_factor_y) * width;
			context.begin_path();
			if l_width < 1.0{
				l_width = 1.0;
			}
			context.set_line_width(l_width as f64);
			let c = JsValue::from(String::from(color));
			context.set_stroke_style(&c);  
			if corner_radius > 0.0{
				let w = (right - left) * self.scale_factor_x;
				let h = (bottom - top) * self.scale_factor_y;  
				let x = (left + self.offset_x) * self.scale_factor_x;
				let	y = (top + self.offset_y) * self.scale_factor_y;  
				let corner = self.scale_factor_x.min(self.scale_factor_y) * corner_radius;
				context.begin_path();
				context.move_to((x + corner) as f64, y as f64);
				context.arc_to((x + w) as f64, y as f64, (x + w) as f64, (y + h) as f64, corner as f64);
				context.arc_to((x + w) as f64, (y + h) as f64, x as f64, (y + h) as f64, corner as f64);
				context.arc_to(x as f64, (y + h) as f64, x as f64, y as f64, corner as f64);
				context.arc_to(x as f64, y as f64, (x + corner) as f64, y as f64, corner as f64);
				context.stroke();
			}else{
				let w = right - left;
				let h = bottom - top;
				context.stroke_rect(((left + self.offset_x) * self.scale_factor_x) as f64, ((top + self.offset_y) * self.scale_factor_y) as f64, (w * self.scale_factor_x) as f64, (h * self.scale_factor_y) as f64);
			}
		}
	}
	/*
	* Draw ellipse
	* context:Drawing context
	* color:Color
	* width:width
	* style:Style
	* left:Left
	* top:Top
	* right:Right
	* bottom:Bottom
	*/
	fn draw_ellipse(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, color:String, width:f32, style:Vec<f32>, left:f32, top:f32, right:f32, bottom:f32){
		if color != "none"{
			let mut l_width = self.scale_factor_x.min(self.scale_factor_y) * width;
			let w = right - left;
			let h = bottom - top;
			context.begin_path();
			if l_width < 1.0{
				l_width = 1.0;
			}
			context.set_line_width(l_width as f64);
			let c = JsValue::from(String::from(color));
			context.set_stroke_style(&c);  
		    
			context.begin_path();
			context.ellipse((((left + (right - left) / 2.0) + self.offset_x) * self.scale_factor_x) as f64, (((top + (bottom - top) / 2.0) + self.offset_y) * self.scale_factor_y) as f64, ((w / 2.0) * self.scale_factor_x) as f64, ((h / 2.0) * self.scale_factor_y) as f64, 0.0, 0.0, core::f64::consts::PI * 2.0).unwrap();
			context.stroke();
		}
	}
	/*
	* Draw text
	* context:Drawing context
	* text:Text
	* color:Color
	* font:Font
	* x:X
	* y:Y
	*/
	fn draw_text(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, text:String, color:String, font:String, x:f32, y:f32){
		if color != "none"{
			let str_split:Vec<&str> = font.split(",").collect();
			let mut new_font = String::from("");
			let px_str = str_split[1];
			let mut num_font : f32 = px_str.parse::<f32>().unwrap();
			num_font = num_font * self.scale_factor_x.min(self.scale_factor_y);
			if str_split[0] == "Default"{
				new_font = num_font.to_string() + "px Arial";
			}else{
				new_font = num_font.to_string() + "px " + str_split[0];
			}
			context.set_font(&new_font);
			let c = JsValue::from(String::from(color));
			context.set_fill_style(&c);  
			context.set_text_align("left");
			context.set_text_baseline("top");
			context.fill_text(&text, ((x + self.offset_x) * self.scale_factor_x) as f64,  ((y + self.offset_y) * self.scale_factor_y) as f64).unwrap();
		}
	}
	/*
	* Draw text
	* context:Drawing context
	* text:Text
	* color:Color
	* font:Font
	* left:Left
	* top:Top
	* right:Right
	* bottom:Bottom
	*/
	fn draw_text_auto_ellipsis(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, text:String, color:String, font:String, left:f32, top:f32, right:f32, bottom:f32){
		if color != "none"{
			let str_split:Vec<&str> = font.split(",").collect();
			let mut new_font = String::from("");
			let px_str = str_split[1];
			let mut num_font : f32 = px_str.parse::<f32>().unwrap();
			num_font = num_font * self.scale_factor_x.min(self.scale_factor_y);
			if str_split[0] == "Default"{
				new_font = num_font.to_string() + "px Arial";
			}else{
				new_font = num_font.to_string() + "px " + str_split[0];
			}
			let c = JsValue::from(String::from(color));
			context.set_fill_style(&c);  
			context.set_text_align("left");
			context.set_text_baseline("middle");
			context.fill_text(&text, ((left + self.offset_x) * self.scale_factor_x) as f64,  ((top + self.offset_y) * self.scale_factor_y) as f64).unwrap();
		}
	}
	/*
	* End paint
	* context:Drawing context
	*/
	fn end_paint(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>){
	}
	/*
	* Fill path
	* context:Drawing context
	* color:Color
	*/
	fn fill_path(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, color:String){
		if color != "none"{
			let c = JsValue::from(String::from(color));
			context.set_fill_style(&c);  
			context.fill();
		}
	}
	/*
	* Fill rect
	* context:Drawing context
	* left:Left
	* top:Top
	* right:Right
	* bottom:Bottom
	*/
	fn fill_rect(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, color:String, left:f32, top:f32, right:f32, bottom:f32){
		if color != "none"{
			let c = JsValue::from(String::from(color));
			context.set_fill_style(&c);
			let w = right - left;
			let h = bottom - top;  
			context.fill_rect(((left + self.offset_x) * self.scale_factor_x) as f64, ((top + self.offset_y) * self.scale_factor_y) as f64, (w * self.scale_factor_x) as f64, (h * self.scale_factor_y) as f64);
		}
	}
	/*
	* Fill rect
	* context:Drawing context
	* left:Left
	* top:Top
	* right:Right
	* bottom:Bottom
	* corner_radius Corner radius
	*/
	fn fill_round_rect(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, color:String, left:f32, top:f32, right:f32, bottom:f32, corner_radius:f32){
		if color != "none"{
			let c = JsValue::from(String::from(color));
			context.set_fill_style(&c);
			if corner_radius > 0.0{
				let w = (right - left) * self.scale_factor_x;
				let h = (bottom - top) * self.scale_factor_y;  
				let x = (left + self.offset_x) * self.scale_factor_x;
				let	y = (top + self.offset_y) * self.scale_factor_y;  
				let corner = self.scale_factor_x.min(self.scale_factor_y) * corner_radius;
				context.begin_path();
				context.move_to((x + corner) as f64, y as f64);
				context.arc_to((x + w) as f64, y as f64, (x + w) as f64, (y + h) as f64, corner as f64);
				context.arc_to((x + w) as f64, (y + h) as f64, x as f64, (y + h) as f64, corner as f64);
				context.arc_to(x as f64, (y + h) as f64, x as f64, y as f64, corner as f64);
				context.arc_to(x as f64, y as f64, (x + corner) as f64, y as f64, corner as f64);
				context.fill();
			}else{
				let w = right - left;
				let h = bottom - top;  
				context.fill_rect(((left + self.offset_x) * self.scale_factor_x) as f64, ((top + self.offset_y) * self.scale_factor_y) as f64, (w * self.scale_factor_x) as f64, (h * self.scale_factor_y) as f64);
			}
		}
	}
	/*
	* Fill ellipse
	* context:Drawing context
	* left:Left
	* top:Top
	* right:Right
	* bottom:Bottom
	*/
	fn fill_ellipse(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, color:String, left:f32, top:f32, right:f32, bottom:f32){
		if color != "none"{
			let c = JsValue::from(String::from(color));
			context.set_fill_style(&c);
			let w = right - left;
			let h = bottom - top;  
			context.begin_path();
			context.ellipse((((left + (right - left) / 2.0) + self.offset_x) * self.scale_factor_x) as f64, (((top + (bottom - top) / 2.0) + self.offset_y) * self.scale_factor_y) as f64, ((w / 2.0) * self.scale_factor_x) as f64, ((h / 2.0) * self.scale_factor_y) as f64, 0.0, 0.0, core::f64::consts::PI * 2.0).unwrap();
			context.fill();
		}
	}
	/*
	* Set clip
	* context:Drawing context
	* left:Left
	* top:Top
	* right:Right
	* bottom:Bottom
	*/
	fn set_clip(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, left:f32, top:f32, right:f32, bottom:f32){
		let w = right - left;
		let h = bottom - top;
		context.begin_path(); 
		context.rect(((left + self.offset_x) * self.scale_factor_x) as f64, ((top + self.offset_y) * self.scale_factor_y) as f64, (w * self.scale_factor_x) as f64, (h * self.scale_factor_y) as f64);
		context.clip();
	}
	/*
	* Set offset
	* context:Drawing context
	* offset_x:Offset x
	* offset_y:Offset y
	*/
	fn set_offset(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, offset_x:f32, offset_y:f32){
		self.offset_x = offset_x;
		self.offset_y = offset_y;
	}
	/*
	* Get text size
	* context:Drawing context
	* text:Text
	* font:Font
	*/
	fn text_size(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, text:String, font:String)->FCSize{
		if text.len() > 0 {
			let str_split:Vec<&str> = font.split(",").collect();
			let mut new_font = String::from("");
			let px_str = str_split[1];
			let num_font : f32 = px_str.parse::<f32>().unwrap();
			if str_split[0] == "Default"{
				new_font = num_font.to_string() + "px Arial";
			}else{
				new_font = num_font.to_string() + "px " + str_split[0];
			}
		    context.set_font(&new_font);
		    let metrics = context.measure_text(&text).expect("REASON");
		    let actual_height = metrics.actual_bounding_box_ascent() + metrics.actual_bounding_box_descent(); 
		    let t_size = FCSize{cx:metrics.width() as f32, cy:actual_height as f32};
		    return t_size;
		}else{
			return FCSize{cx:0.0, cy:0.0};
		}
	}
	/*
	* Save state
	* context:Drawing context
	*/
	fn save(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>){
		context.save();
	}
	/*
	* Restore state
	* context:Drawing context
	*/
	fn restore(&mut self, context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>){
		context.restore();
	}
}

/*
* Base view
*/
#[derive(Clone)]
pub struct FCView{
	allow_drag:bool, //Allow dragging
	allow_resize:bool, //Allow resize
	allow_drag_scroll:bool, //Allow drag scrolling
	back_color:String, //Back color
	back_image:String, //Back image
	border_color:String, //Border color
	border_width:f32, //Border width
	clip_rect:FCRect, //Clip rect
	corner_radius:f32, //Corner radius
	cursor:String, //Cursor
	display_offset:bool, //Display offset
	dock:String, //Dock state
	down_scroll_hbutton:bool, //Whether to press the horizontal scroll bar
	down_scroll_vbutton:bool, //Whether to press the vertical scroll bar
	enabled:bool, //Enabled
	font:String, //Font
	has_clip:bool, //Whether has clip
	hovered_color:String, //Color when hovered
	hscroll_is_visible:bool,
	location:FCPoint, //Location
	margin:FCPadding, //Margin
	padding:FCPadding, //Padding
	pushed_color:String, //Color when pressed
	resize_point:i32, //Resizepoint
	scroll_v:f32, //Vertical scrolling
	scroll_h:f32, //Horizontal scrolling
	scroll_size:f32, //The size of the scroll bar
	show_hscrollbar:bool, //Is the horizontal scroll bar displayed
	show_vscrollbar:bool, //Is the vertical scroll bar displayed
	scroll_barcolor:String, //Color of the scroll bar
	size:FCSize, //Size
	start_scroll_h:f32, //Value to start scrolling
	start_scroll_v:f32, //End scrolling value
	start_point:FCPoint, //Start point
	start_rect:FCRect, //Start rect
	text:String, //Text
	text_color:String, //Text color
	touch_down_time:f64, //Touch down time
	top_most:bool, //TopMost
	view_name:String, //Name
	view_type:String, //Type
	view_id:i32, //Unique ID
	vscroll_is_visible:bool,
	visible:bool //Visible
}

impl FCView{
	fn new()->Self{
		Self{
			allow_drag:false,
			allow_drag_scroll:false,
			allow_resize:false,
			back_color:String::from("rgb(255,255,255)"), 
			back_image:String::from(""),
			border_color:String::from("rgb(100,100,100)"),
			border_width:1.0,
			clip_rect:FCRect{left:0.0, top:0.0, right:0.0, bottom:0.0},
			corner_radius:0.0,
			cursor:String::from(""), 
			display_offset:true,
			dock:String::from("none"),
			down_scroll_hbutton:false,
			down_scroll_vbutton:false,
			enabled:true,
			font:String::from("Default,12"),
			has_clip:false,
			hovered_color:String::from("none"),
			hscroll_is_visible:false,
			location:FCPoint{x:0.0,y:0.0},
			margin:FCPadding{left:0.0, top:0.0, right:0.0, bottom:0.0},
			padding:FCPadding{left:0.0, top:0.0, right:0.0, bottom:0.0},
			pushed_color:String::from("rgb(100,100,100)"),
			resize_point:-1,
			scroll_v:0.0,
			scroll_h:0.0,
			scroll_size:8.0,
			show_hscrollbar:false,
			show_vscrollbar:false,
			scroll_barcolor:String::from("rgb(200,200,200)"),
			size:FCSize{cx:0.0, cy:0.0},
			start_scroll_h:0.0,
			start_scroll_v:0.0,
			start_point:FCPoint{x:0.0,y:0.0},
			start_rect:FCRect{left:0.0, top:0.0, right:0.0, bottom:0.0},
			text:String::from(""),
			text_color:String::from("rgb(0,0,0)"),
			top_most:false,
			touch_down_time:0.0,
			view_name:String::from(""),
			view_type:String::from(""),
			view_id:-1,
			vscroll_is_visible:false,
			visible:true
		}
	}
}

//CheckBox
#[derive(Clone)]
pub struct FCCheckBox{
	button_size:FCSize, //The size of the button
	checked:bool, //Checked
	view:FCView //View
}

impl FCCheckBox{	
	fn new()->Self{
		let view:FCView = FCView::new();
		Self{
			button_size:FCSize{cx:16.0, cy:16.0},
			checked:false,
			view:view
		}
	}
}

//RadioButton
#[derive(Clone)]
pub struct FCRadioButton{
	button_size:FCSize, //The size of the button
	checked:bool, //Checked
	group_name:String, //Group name
	view:FCView //View
}

impl FCRadioButton{
	fn new()->Self{
		let view:FCView = FCView::new();
		Self{
			button_size:FCSize{cx:16.0, cy:16.0},
			checked:false,
			group_name:String::from(""),
			view:view
		}
	}
}

//TabPage
#[derive(Clone)]
pub struct FCTabPage{
	header_button:FCView, //Header button
	view:FCView //View
}

impl FCTabPage{
	fn new()->Self{
		let header_button:FCView = FCView::new();
		let view:FCView = FCView::new();
		Self{
			header_button:header_button,
			view:view
		}
	}
}

//TabView
#[derive(Clone)]
pub struct FCTabView{
	animation_speed:f32, //Animation speed
	layout:String, //Layout
	tab_pages:Vec<FCTabPage>, //Tab pages
	under_line_color:String, //Under line color
	under_line_size:f32, //Under line size
	under_point:FCPoint, //Under line point
	use_animation:bool, //Whether use animation
	view:FCView //View
}

impl FCTabView{
	fn new()->Self{
		let tab_pages:Vec<FCTabPage> = Vec::new();
		let view:FCView = FCView::new();
		Self{
			animation_speed:20.0,
			layout:String::from("top"),
			tab_pages:tab_pages,
			under_line_color:String::from("rgb(255,255,255)"),
			under_line_size:5.0,
			under_point:FCPoint{x:0.0, y:0.0},
			use_animation:false,
			view:view
		}
	}
}

//LayoutDiv
#[derive(Clone)]
pub struct FCLayoutDiv{
	auto_wrap:bool, //Auto wrap
	layout_style:String, //Layout
	view:FCView //View
}

impl FCLayoutDiv{
	fn new()->Self{
		let view:FCView = FCView::new();
		Self{
			auto_wrap:false,
			layout_style:String::from("lefttoright"),
			view:view
		}
	}
}

//SplitLayoutDiv
#[derive(Clone)]
pub struct FCSplitLayoutDiv{
	first_view:FCView, //First view
	layout_style:String, //Layouot style
	old_size:FCSize, //Old size
	second_view:FCView, //Second View
	split_mode:String, //Split mode percentsize or absolutesize
	splitter:FCView, //Splitter
	split_percent:f32, //Split percent
	view:FCView //View
}

impl FCSplitLayoutDiv{
	fn new()->Self{
		let first_view:FCView = FCView::new();
		let second_view:FCView = FCView::new();
		let splitter:FCView = FCView::new();
		let view:FCView = FCView::new();
		Self{
			first_view:first_view,
			layout_style:String::from("lefttoright"),
			old_size:FCSize{cx:0.0, cy:0.0},
			second_view:second_view,
			split_mode:String::from("absolutesize"),
			splitter:splitter,
			split_percent:-1.0,
			view:view
		}
	}
}

//Grid column
#[derive(Clone)]
pub struct FCGridColumn{
	allow_sort:bool, //Allow sort
	allow_resize:bool, //Allow resize
	bounds:FCRect, //Bounds
	back_color:String, //Back color
	border_color:String, //Border color
	col_name:String, //Name
	col_type:String, //Type
	font:String, //Font
	frozen:bool, //Whether is frozen
	index:i32, //Index
	sort:String, //Sort mode
	text:String, //Text
	text_color:String, //Text color
	visible:bool, //Visible
	width:f32 //Width
}

impl FCGridColumn{
	fn new()->Self{
		Self{
			allow_sort:true,
			allow_resize:false,
			back_color:String::from("rgb(255,255,255)"),
			border_color:String::from("rgb(100,100,100)"),
			bounds:FCRect{left:0.0, top:0.0, right:0.0, bottom:0.0},
			col_name:String::from(""),
			col_type:String::from(""),
			font:String::from("Default,12"),
			frozen:false,
			index:-1,
			sort:String::from("none"),
			text:String::from(""),
			text_color:String::from("rgb(0,0,0)"),
			visible:true,
			width:100.0
		}
	}
}

//Grid cell
#[derive(Clone)]
pub struct FCGridCell{
	column:FCGridColumn, //Column
	col_span:i32, //Column span
	back_color:String, //Back color
	border_color:String, //Border color
	font:String, //Font
	row_span:i32, //Row span
	text_color:String, //Text color
	value:String //Value
}

impl FCGridCell{
	fn new()->Self{
		let column:FCGridColumn = FCGridColumn::new();
		Self{
			back_color:String::from("rgb(255,255,255)"),
			border_color:String::from("rgb(100,100,100)"),
			col_span:1,
			column:column,
			font:String::from("Default,12"),
			row_span:1,
			text_color:String::from("rgb(0,0,0)"),
			value:String::from("")
		}
	}
}

//Grid row
#[derive(Clone)]
pub struct FCGridRow{
	cells:Vec<FCGridCell>, //Cells
	selected:bool, //Selected
	visible:bool //Visible
}

impl FCGridRow{
	fn new()->Self{
		let cells:Vec<FCGridCell> = Vec::new();
		Self{
			cells:cells,
			selected:false,
			visible:true
		}
	}
}

//Grid
#[derive(Clone)]
pub struct FCGrid{
	columns:Vec<FCGridColumn>, //Columns
	header_height:f32, //Header height
	rows:Vec<FCGridRow>, //Rows`
	row_height:f32, //Row height 
	selected_row_color:String, //Selected row color
	view:FCView //View
}

impl FCGrid{
	fn new()->Self{
		let columns:Vec<FCGridColumn> = Vec::new();
		let rows:Vec<FCGridRow> = Vec::new();
		let view:FCView = FCView::new();
		Self{
			columns:columns,
			header_height:30.0,
			rows:rows,
			row_height:30.0,
			selected_row_color:String::from("rgb(125,125,125)"),
			view:view			
		}
	}
}

//TextBox
#[derive(Clone)]
pub struct FCTextBox{
	view:FCView //View
}

impl FCTextBox{
	fn new()->Self{
		let view:FCView = FCView::new();
		Self{
			view:view
		}
	}
}

//Security data
#[derive(Clone)]
pub struct SecurityData{
	amount : f64, //Amount value
	close : f64, //Close value
	date : f64, //Date
	high : f64, //High value
	low : f64, //Low value
	open : f64, //Open value
	volume : f64 //Volume value
}

impl SecurityData{
	fn new()->Self{
		Self{
			amount : 0.0,
			close : 0.0,
			date : 0.0,
			high : 0.0,
			low : 0.0,
			open : 0.0,
			volume : 0.0
		}
	}
}

//Plot
#[derive(Clone)]
pub struct FCPlot{
	key1 : f64,  //Key1
	key2 : f64, //Key2
	key3 : f64, //Key3
	line_color : String,  //Line color
	line_width : f32, //Line width
	plot_type : String,  //Plot type
    point_color : String, //Point color
    start_key1 : f64, //Start key1
    start_value1 : f64, //Start value1
    start_key2 : f64, //Start key2
    start_value2 : f64, //Start value2
    start_key3 : f64, //Start key3
    start_value3 : f64, //Start value3
	value1 : f64, //Value1
    value2 : f64, //Value2
    value3 : f64, //Value3
    vid: i32 //Unique ID
}

impl FCPlot{
	fn new()->Self{
		Self{
			key1 : 0.0, 
			key2 : 0.0, 
			key3 :  0.0, 
			line_color : String::from("rgb(255,255,255)"), 
			line_width : 1.0,
			plot_type : String::from("Line"), 
			point_color : String::from("rgba(255,255,255,0.5)"), 
			start_key1 :  0.0, 
			start_value1 :  0.0, 
			start_key2 : 0.0, 
			start_value2 :  0.0, 
			start_key3 :  0.0, 
			start_value3 :  0.0, 
			value1 :  0.0, 
			value2 :  0.0, 
			value3 :  0.0, 
			vid : -1
		}
	}
}

//Chart
#[derive(Clone)]
pub struct FCChart{
	auto_fill_hscale : bool,  //Auto fill scale
	candle_distance : f32, //Distance of candle
	candle_max : f64, //Max value of candle div
    candle_min : f64,   //Min value of candle div
	candle_digit : i32, //Digit of candle
	candle_div_percent : f64, //Percent of candle div
	candle_padding_top : f32,  //Padding top of candle div
    candle_padding_bottom : f32,  //Padding bottom of candle div
	cross_tip_color : String,  //Cross tip color
    cross_line_color : String, //Cross line color
	cross_stop_index : i32, //Cross stop index
    cycle : String, //Cycle
	data : Vec<SecurityData>, //Data collection
	down_color : String,  //Down color
	font : String, //Font
	first_visible_index : i32, //First visible index
	grid_color : String, //Grid color
	hscale_pixel : f32, //HScale interval
	hscale_height: f32,  //HScale height
	ind_max : f64, //Max value of indicator div
    ind_min : f64,  //Min value of indicator div
    ind_max2 : f64, //Max value of indicator div 2
    ind_min2 : f64, //Min value of indicator div 2
	ind_digit : i32, //Digit of indicator div
    ind_digit2 : i32,  //Digit of indicator div 2
	ind_div_percent : f64,  //Percent of indicator div
    ind_div_percent2 : f64, //Percent of indicator div 2
	ind_padding_top : f32,  //Padding top of indicator
    ind_padding_bottom : f32,  //Padding bottom of indicator
    ind_padding_top2 : f32,  //Padding top of indicator 2
    ind_padding_bottom2 : f32,  //Padding bottom of indicator 2
	indicator_colors : Vec<String>, //Indicator colors
	left_vscale_width : f32, //Left vscale width
	last_visible_index : i32, //Last visible index
	last_record_is_visible : bool,  //Whether last record is visible
    last_visible_key : f64,  //Last visible key
	line_width : f32,  //Line width
	main_indicator: String, //Main indicator name
	magnitude : i32, //Magnitude
	plots : Vec<FCPlot>, //Plot collection 
	right_vscale_width : f32,  //Right vscale width
	scale_color : String,  //Scale color
	show_indicator : String, //Show indicator name
	show_cross_line : bool, //Whether show cross line
	select_plot_point : i32,  //Select plot point
	splot : FCPlot,  //Selected plot
    start_move_plot : bool, //Start move plot
	select_shape:String, //Select shape
    select_shape_ex:String, //Select shape extend
	text_color : String, //Text color
	view:FCView, //View
	vol_max : f64, //Max value of volume div
    vol_min : f64, //Min value of volume div
	vol_digit : i32, //Digit of volume div
	vol_div_percent : f64, //Percent of volume div
	vol_padding_top : f32,  //Padding top of volume div
    vol_padding_bottom : f32, //Padding bottom of volume div
	vscale_distance : f32, //Distance of vscale number
    vscale_type : String, //Type of vscale
	up_color : String, //Up color
    first_index_cache : i32, 
    first_touch_index_cache : i32, 
    first_touch_point_cache : FCPoint, 
    last_index_cache : i32,
    second_touch_index_cache : i32,
    second_touch_point_cache : FCPoint,
    touch_position : FCPoint,
    touch_down_position : FCPoint,
    right_space:f32,
    allema12 : Vec<f64>,
    allema26 : Vec<f64>,
    alldifarr : Vec<f64>,
    alldeaarr : Vec<f64>,
    allmacdarr : Vec<f64>,
    boll_up : Vec<f64>,
    boll_down : Vec<f64>,
    boll_mid : Vec<f64>,
    bias1 : Vec<f64>,
    bias2 : Vec<f64>,
    bias3 : Vec<f64>,
    kdj_k : Vec<f64>,
    kdj_d : Vec<f64>,
    kdj_j : Vec<f64>,
    rsi1 : Vec<f64>,
    rsi2 : Vec<f64>,
    rsi3 : Vec<f64>,
    roc : Vec<f64>,
    roc_ma : Vec<f64>,
    wr1 : Vec<f64>,
    wr2 : Vec<f64>,
    cci : Vec<f64>,
    bbi : Vec<f64>,
    trix : Vec<f64>,
    trix_ma : Vec<f64>,
    dma1 : Vec<f64>,
    dma2 : Vec<f64>,
    ma5 : Vec<f64>,
    ma10 : Vec<f64>,
    ma20 : Vec<f64>,
    ma30 : Vec<f64>,
    ma120 : Vec<f64>,
    ma250 : Vec<f64>
}

impl FCChart{
	fn new()->Self{
		let security_datas:Vec<SecurityData> = Vec::new();
		let mut indicator_colors:Vec<String> = Vec::new();
		indicator_colors.push(String::from("rgb(255,255,255)"));
        indicator_colors.push(String::from("rgb(255,255,0)"));
        indicator_colors.push(String::from("rgb(255,0,255)"));
        indicator_colors.push(String::from("rgb(255,0,0)"));
        indicator_colors.push(String::from("rgb(0,255,255)"));
        indicator_colors.push(String::from("rgb(0,255,0)"));
        indicator_colors.push(String::from("rgb(255,255,0)"));
        indicator_colors.push(String::from("rgb(255,255,255)"));
		let plots:Vec<FCPlot> =  Vec::new();
		let splot:FCPlot = FCPlot::new();
		let allema12 = Vec::new();
		let allema26 = Vec::new();
		let alldifarr = Vec::new();
		let alldeaarr = Vec::new();
		let allmacdarr = Vec::new();
		let boll_up = Vec::new();
		let boll_down = Vec::new();
		let boll_mid = Vec::new();
		let bias1 = Vec::new();
		let bias2 = Vec::new();
		let bias3 = Vec::new();
		let kdj_k = Vec::new();
		let kdj_d = Vec::new();
		let kdj_j = Vec::new();
		let rsi1 = Vec::new();
		let rsi2 = Vec::new();
		let rsi3 = Vec::new();
		let roc = Vec::new();
		let roc_ma = Vec::new();
		let wr1 = Vec::new();
		let wr2 = Vec::new();
		let cci = Vec::new();
		let bbi = Vec::new();
		let trix = Vec::new();
		let trix_ma = Vec::new();
		let dma1 = Vec::new();
		let dma2 = Vec::new();
		let view:FCView = FCView::new();
		let ma5 = Vec::new();
		let ma10 = Vec::new();
		let ma20 = Vec::new();
		let ma30 = Vec::new();
		let ma120 = Vec::new();
		let ma250 = Vec::new();
		Self{
			auto_fill_hscale : false, 
			candle_distance : 0.0,
			candle_max : 0.0,
			candle_min : 0.0,
			candle_digit : 2, 
			candle_div_percent : 0.5,
			candle_padding_top : 30.0, 
			candle_padding_bottom : 30.0, 
			cross_tip_color : String::from("rgb(50,50,50)"), 
			cross_line_color : String::from("rgb(100,100,100)"), 
			cross_stop_index : -1,
			cycle : String::from("minute"), 
			data : security_datas,
			down_color : String::from("rgb(15,193,118)"), 
			first_visible_index : -1,
			font : String::from("Default,12"), 
			grid_color : String::from("rgba(100,100,100,0.5)"), 
			hscale_pixel : 11.0,
			hscale_height: 30.0, 
			ind_max : 0.0,
			ind_min : 0.0,
            ind_max2 : 0.0,
			ind_min2 : 0.0,
			ind_digit : 2, 
            ind_digit2 : 2, 
			ind_div_percent : 0.3, 
            ind_div_percent2 : 0.0, 
			ind_padding_top : 20.0, 
			ind_padding_bottom : 20.0, 
            ind_padding_top2 : 20.0, 
			ind_padding_bottom2 : 20.0, 
			indicator_colors : indicator_colors, 
			last_visible_index : -1, 
			last_record_is_visible : true, 
			last_visible_key : 0.0, 
			left_vscale_width : 100.0,
			line_width:1.0,
			main_indicator : String::from("MA"), 
			magnitude : 1,
			plots : plots, 
			right_vscale_width : 100.0, 
			right_space:0.0,
			scale_color : String::from("rgb(100,100,100)"), 
			show_indicator : String::from("MACD"), 
			show_cross_line : false,
			select_plot_point : -1, 
			splot : splot, 
			start_move_plot : false,
			select_shape : String::from(""),
			select_shape_ex : String::from(""),
			text_color : String::from("rgb(255,255,255)"),
			touch_position : FCPoint{x:0.0, y:0.0},
			touch_down_position : FCPoint{x:0.0, y:0.0},
			up_color : String::from("rgb(219,68,83)"), 
			view:view,
			vol_max : 0.0,
			vol_min : 0.0,
			vol_digit : 0,
			vol_div_percent : 0.2,
			vol_padding_top : 20.0, 
			vol_padding_bottom : 0.0,
			vscale_distance : 35.0,
			vscale_type : String::from("standard"), 
			first_index_cache : -1,
			first_touch_index_cache : -1,
			first_touch_point_cache : FCPoint{x:0.0, y:0.0},
			last_index_cache : -1,
			second_touch_index_cache : -1,
			second_touch_point_cache : FCPoint{x:0.0, y:0.0},
			allema12 : allema12,
			allema26 : allema26,
			alldifarr : alldifarr,
			alldeaarr : alldeaarr,
			allmacdarr : allmacdarr,
			boll_up : boll_up,
			boll_down : boll_down,
			boll_mid : boll_mid,
			bias1 : bias1,
			bias2 : bias2,
			bias3 : bias3,
			kdj_k : kdj_k,
			kdj_d : kdj_d,
			kdj_j : kdj_j,
			rsi1 : rsi1,
			rsi2 : rsi2,
			rsi3 : rsi3,
			roc : roc,
			roc_ma : roc_ma,
			wr1 : wr1,
			wr2 : wr2,
			cci : cci,
			bbi : bbi,
			trix : trix,
			trix_ma : trix_ma,
			dma1 : dma1,
			dma2 : dma2,
			ma5 : ma5,
			ma10 : ma10,
			ma20 : ma20,
			ma30 : ma30,
			ma120 : ma120,
			ma250 : ma250
		}
	}
}

/*
*Number to decimal places
*value:Value
*digit:Digit
*/
pub fn to_fixed(value:f64, digit:i32)->String{
	if digit == 1{
		return format!("{:.1}", value);
	}else if digit == 2{
		return format!("{:.2}", value);
	}else if digit == 3{
		return format!("{:.3}", value);
	}else if digit == 4{
		return format!("{:.4}", value);
	}else if digit == 5{
		return format!("{:.5}", value);
	}else if digit == 6{
		return format!("{:.6}", value);
	}else if digit == 7{
		return format!("{:.7}", value);
	}else if digit == 8{
		return format!("{:.8}", value);
	}else if digit == 9{
		return format!("{:.9}", value);
	}else{
		return (value as i64).to_string();
	}
}

/*
 * Create new id
 */
pub fn create_new_id()->i32{
	let mut vid:i32 = 0;
	unsafe{
		M_NOW_ID = M_NOW_ID + 1;
		vid = M_NOW_ID;
    }
    return vid;
}

/*
 * Add top-level view
 * view:Target view
 */
pub fn add_view(view:FCView)->i32{
	let new_id = create_new_id();
	let mut add_view = view.clone();
	add_view.view_id = new_id;
	M_VIEW_MAP.lock().unwrap().insert(new_id, add_view);
	return new_id;
}

/*
 * Add to parent view
 * view:Target view
 * parent:Parent view
 */
pub fn add_view_to_parent(view:FCView, parent:FCView)->i32{
	let new_id = create_new_id();
	let mut add_view = view.clone();
	add_view.view_id = new_id;
	let parent_id = parent.view_id;
	M_VIEW_MAP.lock().unwrap().insert(new_id, add_view);
	M_PARENT_VIEW_MAP.lock().unwrap().insert(new_id, parent_id);
	return new_id;
}

/*
 * Get subview collection
 * parent:Parent view
 */
pub fn get_sub_views(parent:FCView)->Vec<FCView>{
	let mut sub_views:Vec<FCView> = Vec::new();
	for (k, v) in &*M_VIEW_MAP.lock().unwrap() {
		match M_PARENT_VIEW_MAP.lock().unwrap().get(&k) {
			Some(x) => {
				if x == &parent.view_id{
					sub_views.push(v.clone());
				}
			},
			None => {
			}
		}
    }
	return sub_views;
}

/*
 * Get top-level views
 */
pub fn get_top_views()->Vec<FCView>{
	let mut sub_views:Vec<FCView> = Vec::new();
	for (k, v) in &*M_VIEW_MAP.lock().unwrap() {
		match M_PARENT_VIEW_MAP.lock().unwrap().get(&k) {
			Some(x) => {
			},
			None => {
				sub_views.push(v.clone());
			}
		}
    }
	return sub_views;
}

/*
* Obtain absolute position X
* view:Target view
*/
pub fn client_x(view:FCView)->f32{
	if view.view_id != -1{
		let c_left = view.location.x;
		let mut find = false;
		match M_PARENT_VIEW_MAP.lock().unwrap().get(&view.view_id) {
			Some(x) => {
				find = true;	
			},
			None => {
				find = false;
			}
		}
		if find{
			let p_id = M_PARENT_VIEW_MAP.lock().unwrap()[&view.view_id];
			let parent = M_VIEW_MAP.lock().unwrap()[&p_id].clone();
			if parent.display_offset {
				return c_left - parent.scroll_h + client_x(parent);
			}else{
				return c_left + client_x(parent);
			}
		}else{
			return c_left;
		}
	}else{
		return 0.0;
	}
}

/*
* Obtain absolute position Y
* view:Target view
*/
pub fn client_y(view:FCView)->f32{
	if view.view_id != -1 {
		let c_top = view.location.y;
		let mut find = false;
		match M_PARENT_VIEW_MAP.lock().unwrap().get(&view.view_id) {
			Some(x) => {
				find = true;	
			},
			None => {
				find = false;
				
			}
		}
		if find {
			let p_id = M_PARENT_VIEW_MAP.lock().unwrap()[&view.view_id];
			let parent = M_VIEW_MAP.lock().unwrap()[&p_id].clone();
			if parent.display_offset{
				return c_top - parent.scroll_v + client_y(parent);
			}else{
				return c_top + client_y(parent);
			}
		}else{
			return c_top;
		}
	}else{
		return 0.0;
	}
}

/*
* Does it include coordinates
* view:Target view
* mp:Coordinate
*/
pub fn contains_point(view:FCView, mp:FCPoint)->bool{
	let clx = client_x(view.clone());
	let cly = client_y(view.clone());
	let size = view.size;
	let cp = FCPoint{x:mp.x - clx, y:mp.y - cly};
	if cp.x >= 0.0 && cp.x <= size.cx &&
		cp.y >= 0.0 && cp.y <= size.cy {
		return true;
	} else {
		return false;
	}
}

/*
* Find view by name
* name:Name of view
* views:View collection
*/
pub fn find_view_by_name(name:String, views:Vec<FCView>)->FCView{
	let none_view = M_NONE_VIEW.lock().unwrap().clone();
	let copy_name = name.clone();
	 for i in 0..views.len(){
		let view = &views[i];
		if view.view_name == copy_name{
		    return view.clone();
		}else{
			let sub_views = get_sub_views(view.clone());
			if sub_views.len() > 0{
				let sub_view = find_view_by_name(name.clone(), sub_views);
				if sub_view.view_id != -1 {
					return sub_view;
				}
			}
		}
	}
	return none_view;
}

/*
* Is it visible when redrawn
* view:Target view
*/
pub fn is_paint_visible(view:FCView)->bool{
	if view.visible{
		let mut find = false;
        match M_PARENT_VIEW_MAP.lock().unwrap().get(&view.view_id) {
			Some(x) => {
				find = true;
			},
			None => {
				find = false;
			}
		}
		if find{
			let p_id = M_PARENT_VIEW_MAP.lock().unwrap()[&view.view_id];
			let parent = M_VIEW_MAP.lock().unwrap()[&p_id].clone();
			if parent.visible {
				return is_paint_visible(parent);
			}else{
				return false;
			}
		}else{
			return true;
		}
    }else{
        return false;
     }
}

/*
* Is it enabled when operate
* view:Target view
*/
pub fn is_view_enabled(view:FCView)->bool{
	if view.enabled{
		let mut find = false;
        match M_PARENT_VIEW_MAP.lock().unwrap().get(&view.view_id) {
			Some(x) => {
				find = true;
			},
			None => {
				find = false;
			}
		}
		if find{
			let p_id = M_PARENT_VIEW_MAP.lock().unwrap()[&view.view_id];
			let parent = M_VIEW_MAP.lock().unwrap()[&p_id].clone();
			if parent.enabled {
				return is_view_enabled(parent);
			}else{
				return false;
			}
		}else{
			return true;
		}
    }else{
        return false;
     }
}

/*
* Obtain the intersection of regions
*/
pub fn get_intersect_rect(lp_dest_rect:&mut FCRect, lp_src1_rect:FCRect, lp_src2_rect:FCRect)->i32{
	lp_dest_rect.left = lp_src1_rect.left.max(lp_src2_rect.left);
    lp_dest_rect.right = lp_src1_rect.right.min(lp_src2_rect.right);
    lp_dest_rect.top = lp_src1_rect.top.max(lp_src2_rect.top);
    lp_dest_rect.bottom = lp_src1_rect.bottom.min(lp_src2_rect.bottom);
    if lp_dest_rect.right > lp_dest_rect.left && lp_dest_rect.bottom > lp_dest_rect.top{
        return 1;
    }
    else{
        lp_dest_rect.left = 0.0;
        lp_dest_rect.right = 0.0;
        lp_dest_rect.top = 0.0;
        lp_dest_rect.bottom = 0.0;
        return 0;
    }
}

/*
* Function to start touching
*/
pub fn touch_start(context: &std::rc::Rc<web_sys::CanvasRenderingContext2d>, pressed: &std::rc::Rc<std::cell::Cell<bool>>, canvas: &web_sys::HtmlCanvasElement) {
    let context = context.clone();
    let pressed = pressed.clone();
    let closure = Closure::wrap(Box::new(move |event: web_sys::TouchEvent| {
        unsafe{
			M_IS_MOBILE = true;
			let scale_factor_x = M_PAINT.lock().unwrap().scale_factor_x;
			let scale_factor_y = M_PAINT.lock().unwrap().scale_factor_y;
			if M_IS_MOBILE {
				let touches = event.touches();
				let touch1 = touches.get(0).expect("REASON");
				let mp = FCPoint{x:touch1.client_x() as f32 / scale_factor_x as f32, y:touch1.client_y() as f32 / scale_factor_y as f32};
				M_TOUCH_POINT = FCPoint{x:mp.x, y:mp.y};
				M_TOUCH_DOWN_POINT = FCPoint{x:mp.x, y:mp.y};
				let top_views = get_top_views();
				let mut touch_down_view = find_view(M_TOUCH_DOWN_POINT.clone(), top_views);
				M_TOUCH_DOWN_VIEW = touch_down_view.view_id;
    			/*if let Ok(duration) = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
					let newClickTime:i64 = duration.as_millis() as i64; 
					if newClickTime - M_LASTCLICKTIME < 250{
						M_IS_DOUBLECLICK = true;
						M_LASTCLICKTIME = 0;
						clicks = 2;
					}else{
						M_IS_DOUBLECLICK = true;
						M_LASTCLICKTIME = newClickTime;
					}
				}*/
				if M_TOUCH_DOWN_VIEW != -1 && is_view_enabled(touch_down_view.clone()){
					let last_focuesd_view = M_FOCUSED_VIEW;
					M_FOCUSED_VIEW = M_TOUCH_DOWN_VIEW;
					M_FIRST_TOUCH = false;
					M_SECOND_TOUCH = false;
					M_TOUCH_FIRST_POINT = FCPoint{x:0.0, y:0.0};
					M_TOUCH_SECOND_POINT = FCPoint{x:0.0, y:0.0};
					let clx = client_x(touch_down_view.clone());
					let cly = client_y(touch_down_view.clone());
					if touches.length() >= 1 {
						M_FIRST_TOUCH = true;
						M_TOUCH_DOWN_POINT = FCPoint{x:touch1.client_x() as f32 / scale_factor_x as f32, y:touch1.client_y() as f32 / scale_factor_y as f32};
						M_TOUCH_FIRST_POINT = FCPoint{x:mp.x, y:mp.y};
						M_TOUCH_FIRST_POINT.x = M_TOUCH_FIRST_POINT.x - clx;
						M_TOUCH_FIRST_POINT.y = M_TOUCH_FIRST_POINT.y - cly;
					}
					if touches.length() >= 2 {
						let touch2 = touches.get(1).expect("REASON");
						M_SECOND_TOUCH = true;
						M_TOUCH_SECOND_POINT = FCPoint{x:touch2.client_x() as f32 / scale_factor_x as f32, y:touch2.client_y() as f32 / scale_factor_y as f32};
						M_TOUCH_SECOND_POINT.x = M_TOUCH_SECOND_POINT.x - clx;
						M_TOUCH_SECOND_POINT.y = M_TOUCH_SECOND_POINT.y - cly;
					}
					on_touch_start(&context, touch_down_view.clone(), M_FIRST_TOUCH, M_TOUCH_FIRST_POINT.clone(), M_SECOND_TOUCH, M_TOUCH_SECOND_POINT.clone());
					let window = web_sys::window().expect("should have a window in this context");
					let document = window.document().expect("window should have a document");
					let input: web_sys::HtmlInputElement = document.get_element_by_id("RUSTINPUTTEXT").unwrap().dyn_into().unwrap();
					let mut show_text_box =  false;
					if M_FOCUSED_VIEW != -1{
						let focused_view = M_VIEW_MAP.lock().unwrap()[&M_FOCUSED_VIEW].clone();
						if focused_view.view_type == "textbox"{
							if last_focuesd_view != -1{
								let mut focused_view2 = M_VIEW_MAP.lock().unwrap()[&last_focuesd_view].clone();
								if focused_view2.view_type == "textbox"{
									focused_view2.text = input.value();
									M_VIEW_MAP.lock().unwrap().insert(last_focuesd_view, focused_view2.clone());
									invalidate_view(&context, focused_view2.clone());
								}
							}
							input.style().set_property("display", "block").unwrap();
							let scale_factor_x = M_PAINT.lock().unwrap().scale_factor_x;
							let scale_factor_y = M_PAINT.lock().unwrap().scale_factor_y;
							let left_str = (client_x(focused_view.clone()) * scale_factor_x).to_string() + &"px";
							input.style().set_property("left", &left_str).unwrap();
							let top_str = (client_y(focused_view.clone()) * scale_factor_y).to_string() + &"px";
							input.style().set_property("top", &top_str).unwrap();
							let width_str = (focused_view.size.cx * scale_factor_x).to_string() + &"px";
							input.style().set_property("width", &width_str).unwrap();
							let height_str = (focused_view.size.cy * scale_factor_y).to_string() + &"px";
							input.style().set_property("height", &height_str).unwrap();
							input.style().set_property("background-color", &focused_view.back_color).unwrap();
							input.style().set_property("color", &focused_view.text_color).unwrap();
							let border_str = "1px solid ".to_string() + &focused_view.border_color;
							input.style().set_property("border", &border_str).unwrap();
							let str_split:Vec<&str> = focused_view.font.split(",").collect();
							let mut new_font = String::from("");
							let px_str = str_split[1];
							let mut num_font : f32 = px_str.parse::<f32>().unwrap();
							num_font = scale_factor_x.min(scale_factor_y) * num_font;
							if str_split[0] == "Default"{
								new_font = num_font.to_string() + "px Arial";
							}else{
								new_font = num_font.to_string() + "px " + str_split[0];
							}
							input.style().set_property("font", &new_font).unwrap();
							input.set_value(&focused_view.text);
							let event = web_sys::Event::new("click").unwrap();
							input.dispatch_event(&event).unwrap();
							show_text_box = true;
						}
					}
					if !show_text_box{
						if last_focuesd_view != -1{
							let mut focused_view2 = M_VIEW_MAP.lock().unwrap()[&last_focuesd_view].clone();
							if focused_view2.view_type == "textbox"{
								input.style().set_property("display", "none").unwrap();
								focused_view2.text = input.value();
								M_VIEW_MAP.lock().unwrap().insert(last_focuesd_view, focused_view2.clone());
								invalidate_view(&context, focused_view2.clone());								
							}
						}
					}
					if touch_down_view.allow_resize{
						touch_down_view.resize_point = get_resize_state(touch_down_view.clone(), M_TOUCH_FIRST_POINT.clone());
						if touch_down_view.resize_point != -1{
							touch_down_view.start_rect = FCRect{left:touch_down_view.location.x, top:touch_down_view.location.y, right:touch_down_view.location.x + touch_down_view.size.cx,
								bottom:touch_down_view.location.y + touch_down_view.size.cy};
							M_VIEW_MAP.lock().unwrap().insert(touch_down_view.view_id, touch_down_view.clone());
						}
					}
				}
			}
		}
    }) as Box<dyn FnMut(_)>);
    canvas.add_event_listener_with_callback("touchstart", closure.as_ref().unchecked_ref()).unwrap();
    closure.forget();
}

/*
* Touch move function
*/
pub fn touch_move(context: &std::rc::Rc<web_sys::CanvasRenderingContext2d>, pressed: &std::rc::Rc<std::cell::Cell<bool>>, canvas: &web_sys::HtmlCanvasElement) {
    let context = context.clone();
    let pressed = pressed.clone();
    let closure = Closure::wrap(Box::new(move |event: web_sys::TouchEvent| {
        unsafe{
			let scale_factor_x = M_PAINT.lock().unwrap().scale_factor_x;
			let scale_factor_y = M_PAINT.lock().unwrap().scale_factor_y;
			if M_IS_MOBILE{
				if M_TOUCH_DOWN_VIEW != -1{
					let mut touch_down_view = M_VIEW_MAP.lock().unwrap()[&M_TOUCH_DOWN_VIEW].clone();
					let touches = event.touches();
					let touch1 = touches.get(0).expect("REASON");
					M_FIRST_TOUCH = false;
					M_SECOND_TOUCH = false;
					M_TOUCH_FIRST_POINT = FCPoint{x:0.0, y:0.0};
					M_TOUCH_SECOND_POINT = FCPoint{x:0.0, y:0.0};
					let clx = client_x(touch_down_view.clone());
					let cly = client_y(touch_down_view.clone());
					let mp = FCPoint{x:touch1.client_x() as f32 / scale_factor_x as f32, y:touch1.client_y() as f32 / scale_factor_y as f32};
					if touches.length() >= 1 {
						M_FIRST_TOUCH = true;
						M_TOUCH_FIRST_POINT = FCPoint{x:touch1.client_x() as f32 / scale_factor_x as f32, y:touch1.client_y() as f32 / scale_factor_y as f32};
						M_TOUCH_POINT = M_TOUCH_FIRST_POINT.clone();
						M_TOUCH_FIRST_POINT.x = M_TOUCH_FIRST_POINT.x - clx;
						M_TOUCH_FIRST_POINT.y = M_TOUCH_FIRST_POINT.y - cly;
					}
					if touches.length() >= 2 {
						let touch2 = touches.get(1).expect("REASON");
						M_SECOND_TOUCH = true;
						M_TOUCH_SECOND_POINT = FCPoint{x:touch2.client_x() as f32 / scale_factor_x as f32, y:touch2.client_y() as f32 / scale_factor_y as f32};
						M_TOUCH_SECOND_POINT.x = M_TOUCH_SECOND_POINT.x - clx;
						M_TOUCH_SECOND_POINT.y = M_TOUCH_SECOND_POINT.y - cly;
					}
					on_touch_move(&context, touch_down_view.clone(), M_FIRST_TOUCH, M_TOUCH_FIRST_POINT.clone(), M_SECOND_TOUCH, M_TOUCH_SECOND_POINT.clone());
					if touch_down_view.resize_point != -1{
						let mut new_bounds = FCRect{left:touch_down_view.start_rect.left, top:touch_down_view.start_rect.top, right:touch_down_view.start_rect.right, bottom:touch_down_view.start_rect.bottom};
						window_resize(&mut new_bounds, touch_down_view.resize_point, mp.clone(), M_TOUCH_DOWN_POINT.clone());
						touch_down_view.location = FCPoint{x:new_bounds.left, y:new_bounds.top};
						touch_down_view.size = FCSize{cx:new_bounds.right - new_bounds.left, cy:new_bounds.bottom - new_bounds.top};
						M_VIEW_MAP.lock().unwrap().insert(touch_down_view.view_id, touch_down_view.clone());
						let mut find:bool = false;
						let mut p_id:i32 = 0;
						match M_PARENT_VIEW_MAP.lock().unwrap().get(&touch_down_view.view_id) {
							Some(x) => {
								find = true;
								p_id = *x;	
							},
							None => {
								find = false;
							}
						}
						if find {
							let parent_view = M_VIEW_MAP.lock().unwrap()[&p_id].clone();
							invalidate_view(&context, parent_view.clone());
						}else{
							invalidate(&context);
						}
					}
					else if touch_down_view.allow_drag{
						if (mp.x - M_TOUCH_DOWN_POINT.x).abs() > 5.0 || (mp.y - M_TOUCH_DOWN_POINT.y).abs() > 5.0 {
							M_DRAG_BEGIN_POINT = FCPoint{x:M_TOUCH_DOWN_POINT.x, y:M_TOUCH_DOWN_POINT.y};
							M_DRAGGING_VIEW = M_TOUCH_DOWN_VIEW;
							M_DRAG_BEGIN_RECT = FCRect{left:touch_down_view.location.x, top:touch_down_view.location.y,
							right:touch_down_view.location.x + touch_down_view.size.cx,
							bottom:touch_down_view.location.y + touch_down_view.size.cy};
							M_TOUCH_DOWN_VIEW = -1;
						}
					}
				} else if M_DRAGGING_VIEW != -1{
					let touches = event.touches();
					let touch1 = touches.get(0).expect("REASON");
					let mp = FCPoint{x:touch1.client_x() as f32 / scale_factor_x as f32, y:touch1.client_y() as f32 / scale_factor_y as f32};
					let offset_x:f32 = mp.x - M_DRAG_BEGIN_POINT.x;
					let offset_y:f32 = mp.y - M_DRAG_BEGIN_POINT.y;
					let new_bounds = FCRect{left:M_DRAG_BEGIN_RECT.left + offset_x, top:M_DRAG_BEGIN_RECT.top + offset_y,
						right:M_DRAG_BEGIN_RECT.right + offset_x, bottom:M_DRAG_BEGIN_RECT.bottom + offset_y};
					let mut dragging_view = M_VIEW_MAP.lock().unwrap()[&M_DRAGGING_VIEW].clone();
					dragging_view.location = FCPoint{x:new_bounds.left, y:new_bounds.top};
					M_VIEW_MAP.lock().unwrap().insert(dragging_view.view_id, dragging_view.clone());
					let mut find:bool = false;
					let mut p_id:i32 = 0;
					match M_PARENT_VIEW_MAP.lock().unwrap().get(&dragging_view.view_id) {
						Some(x) => {
							find = true;
							p_id = *x;	
						},
						None => {
							find = false;
						}
					}
					if find{
						let parent_view = M_VIEW_MAP.lock().unwrap()[&p_id].clone();
						if parent_view.view_type == "split"{
							for (_vid, v) in M_SPLIT_MAP.lock().unwrap().iter_mut(){
								if parent_view.view_id == *_vid{
									(*v).splitter = dragging_view.clone();
									reset_split_layout_div(&mut *v);
								}
							}
						}
						invalidate_view(&context, parent_view.clone());
					}else{
						invalidate(&context);
					}
				}
			}
		}
    }) as Box<dyn FnMut(_)>);
    canvas.add_event_listener_with_callback("touchmove", closure.as_ref().unchecked_ref()).unwrap();
    closure.forget();
}

/*
* End touch function
*/
pub fn touch_end(context: &std::rc::Rc<web_sys::CanvasRenderingContext2d>, pressed: &std::rc::Rc<std::cell::Cell<bool>>, canvas: &web_sys::HtmlCanvasElement) {
    let context = context.clone();
    let pressed = pressed.clone();
    let closure = Closure::wrap(Box::new(move |event: web_sys::TouchEvent| {
        unsafe{
			if M_IS_MOBILE{
				if M_TOUCH_DOWN_VIEW != -1{
					let mut touch_down_view = M_VIEW_MAP.lock().unwrap()[&M_TOUCH_DOWN_VIEW].clone();
					let top_views = get_top_views();
					let view = find_view(M_TOUCH_POINT.clone(), top_views);
					let mut clicks = 1;
					if M_IS_DOUBLECLICK{
						clicks = 2;
					}
					if view.view_id == M_TOUCH_DOWN_VIEW{
						on_click(&context, touch_down_view.clone(), M_FIRST_TOUCH, M_TOUCH_FIRST_POINT.clone(), M_SECOND_TOUCH, M_TOUCH_SECOND_POINT.clone(), clicks);
					}
					if touch_down_view.allow_resize{
						touch_down_view.resize_point = -1;
						M_VIEW_MAP.lock().unwrap().insert(touch_down_view.view_id, touch_down_view.clone());
					}
					M_TOUCH_DOWN_VIEW = -1;
					on_touch_end(&context, touch_down_view.clone(), M_FIRST_TOUCH, M_TOUCH_FIRST_POINT.clone(), M_SECOND_TOUCH, M_TOUCH_SECOND_POINT.clone());
				}
				M_DRAGGING_VIEW = -1;
			}
		}
    }) as Box<dyn FnMut(_)>);
    canvas.add_event_listener_with_callback("touchend", closure.as_ref().unchecked_ref()).unwrap();
    closure.forget();
}

/*
* Mouse wheel function
*/
pub fn mouse_wheel(context: &std::rc::Rc<web_sys::CanvasRenderingContext2d>, pressed: &std::rc::Rc<std::cell::Cell<bool>>, canvas: &web_sys::HtmlCanvasElement) {
    let context = context.clone();
    let pressed = pressed.clone();
    let closure = Closure::wrap(Box::new(move |event: web_sys::WheelEvent| {
        unsafe{
			if !M_IS_MOBILE{
				let scale_factor_x = M_PAINT.lock().unwrap().scale_factor_x;
				let scale_factor_y = M_PAINT.lock().unwrap().scale_factor_y;
				let mp = FCPoint{x:event.offset_x() as f32 / scale_factor_x as f32, y:event.offset_y() as f32 / scale_factor_y as f32};
				let top_views = get_top_views();
				let find_view = find_view(mp.clone(), top_views);
				let cmp  = FCPoint{x:mp.x - client_x(find_view.clone()), y:mp.y - client_y(find_view.clone())};
				let delta_y = event.delta_y();
				let mut delta:i32 = 0;
				if delta_y > 0.0{
					delta = -1;
				}else if delta_y < 0.0{
					delta = 1;
				}
				on_mouse_wheel(&context, find_view.clone(), cmp.clone(), 0, 0, delta);
			}
		}
    }) as Box<dyn FnMut(_)>);
    canvas.add_event_listener_with_callback("mousewheel", closure.as_ref().unchecked_ref()).unwrap();
	canvas.add_event_listener_with_callback("DOMMouseScroll", closure.as_ref().unchecked_ref()).unwrap();
    closure.forget();
}

/*
* Mouse up function
*/
pub fn mouse_up(context: &std::rc::Rc<web_sys::CanvasRenderingContext2d>, pressed: &std::rc::Rc<std::cell::Cell<bool>>, canvas: &web_sys::HtmlCanvasElement) {
    let context = context.clone();
    let pressed = pressed.clone();
    let closure = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| {
        pressed.set(false);
        unsafe{
			if !M_IS_MOBILE{
				if M_TOUCH_DOWN_VIEW != -1{
					let scale_factor_x = M_PAINT.lock().unwrap().scale_factor_x;
					let scale_factor_y = M_PAINT.lock().unwrap().scale_factor_y;
					let mp = FCPoint{x:event.offset_x() as f32 / scale_factor_x as f32, y:event.offset_y() as f32 / scale_factor_y as f32};
					let mut touch_down_view = M_VIEW_MAP.lock().unwrap()[&M_TOUCH_DOWN_VIEW].clone();
					let cmp  = FCPoint{x:mp.x - client_x(touch_down_view.clone()), y:mp.y - client_y(touch_down_view.clone())};
					let top_views = get_top_views();
					let find_view = find_view(mp.clone(), top_views);
					let mut clicks = 1;
					if M_IS_DOUBLECLICK{
						clicks = 2;
					}
					if find_view.view_id == M_TOUCH_DOWN_VIEW{
						on_click(&context, touch_down_view.clone(), true, cmp.clone(), false, cmp.clone(), clicks);
					}
					if touch_down_view.allow_resize{
						touch_down_view.resize_point = -1;
						M_VIEW_MAP.lock().unwrap().insert(touch_down_view.view_id, touch_down_view.clone());
					}
					M_TOUCH_DOWN_VIEW = -1;
					M_TOUCH_MOVE_VIEW = -1;
					on_mouse_up(&context, touch_down_view.clone(), cmp.clone(), 1, clicks, 0);
				}
				M_DRAGGING_VIEW = -1;
			}
		}
    }) as Box<dyn FnMut(_)>);
    canvas.add_event_listener_with_callback("mouseup", closure.as_ref().unchecked_ref()).unwrap();
    closure.forget();
}

/*
* Mouse move function
*/
pub fn mouse_move(context: &std::rc::Rc<web_sys::CanvasRenderingContext2d>, pressed: &std::rc::Rc<std::cell::Cell<bool>>, canvas: &web_sys::HtmlCanvasElement){
    let context = context.clone();
    let pressed = pressed.clone();
    let closure = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| {
        unsafe{
			if !M_IS_MOBILE{
				let scale_factor_x = M_PAINT.lock().unwrap().scale_factor_x;
				let scale_factor_y = M_PAINT.lock().unwrap().scale_factor_y;
				let mp = FCPoint{x:event.offset_x() as f32 / scale_factor_x as f32, y:event.offset_y() as f32 / scale_factor_y as f32};
				if M_TOUCH_DOWN_VIEW != -1{
					let mut touch_down_view = M_VIEW_MAP.lock().unwrap()[&M_TOUCH_DOWN_VIEW].clone();
					M_TOUCH_MOVE_VIEW = touch_down_view.view_id;
					let cmp = FCPoint{x:mp.x - client_x(touch_down_view.clone()), y:mp.y - client_y(touch_down_view.clone())};
					on_mouse_move(&context, touch_down_view.clone(), cmp.clone(), 1, 1, 0);
					if touch_down_view.resize_point != -1{
						let mut new_bounds = FCRect{left:touch_down_view.start_rect.left, top:touch_down_view.start_rect.top, right:touch_down_view.start_rect.right, bottom:touch_down_view.start_rect.bottom};
						window_resize(&mut new_bounds, touch_down_view.resize_point, mp.clone(), M_TOUCH_DOWN_POINT.clone());
						touch_down_view.location = FCPoint{x:new_bounds.left, y:new_bounds.top};
						touch_down_view.size = FCSize{cx:new_bounds.right - new_bounds.left, cy:new_bounds.bottom - new_bounds.top};
						M_VIEW_MAP.lock().unwrap().insert(touch_down_view.view_id, touch_down_view.clone());
						let mut find:bool = false;
						let mut p_id:i32 = 0;
						match M_PARENT_VIEW_MAP.lock().unwrap().get(&touch_down_view.view_id) {
							Some(x) => {
								find = true;
								p_id = *x;	
							},
							None => {
								find = false;
							}
						}
						if find {
							let parent_view = M_VIEW_MAP.lock().unwrap()[&p_id].clone();
							invalidate_view(&context, parent_view.clone());
						}else{
							invalidate(&context);
						}
					}
					else if touch_down_view.allow_drag{
						if (mp.x - M_TOUCH_DOWN_POINT.x).abs() > 5.0 || (mp.y - M_TOUCH_DOWN_POINT.y).abs() > 5.0 {
							M_DRAG_BEGIN_POINT = FCPoint{x:M_TOUCH_DOWN_POINT.x, y:M_TOUCH_DOWN_POINT.y};
							M_DRAGGING_VIEW = M_TOUCH_DOWN_VIEW;
							M_DRAG_BEGIN_RECT = FCRect{left:touch_down_view.location.x, top:touch_down_view.location.y,
							right:touch_down_view.location.x + touch_down_view.size.cx,
							bottom:touch_down_view.location.y + touch_down_view.size.cy};
							M_TOUCH_DOWN_VIEW = -1;
						}
					}
				}
				else if M_DRAGGING_VIEW != -1{
					let offset_x:f32 = mp.x - M_DRAG_BEGIN_POINT.x;
					let offset_y:f32 = mp.y - M_DRAG_BEGIN_POINT.y;
					let new_bounds = FCRect{left:M_DRAG_BEGIN_RECT.left + offset_x, top:M_DRAG_BEGIN_RECT.top + offset_y,
						right:M_DRAG_BEGIN_RECT.right + offset_x, bottom:M_DRAG_BEGIN_RECT.bottom + offset_y};
					let mut dragging_view = M_VIEW_MAP.lock().unwrap()[&M_DRAGGING_VIEW].clone();
					dragging_view.location = FCPoint{x:new_bounds.left, y:new_bounds.top};
					M_VIEW_MAP.lock().unwrap().insert(dragging_view.view_id, dragging_view.clone());
					let mut find:bool = false;
					let mut p_id:i32 = 0;
					match M_PARENT_VIEW_MAP.lock().unwrap().get(&dragging_view.view_id) {
						Some(x) => {
							find = true;
							p_id = *x;	
						},
						None => {
							find = false;
						}
					}
					if find {
						let parent_view = M_VIEW_MAP.lock().unwrap()[&p_id].clone();
						if parent_view.view_type == "split"{
							for (_vid, v) in M_SPLIT_MAP.lock().unwrap().iter_mut(){
								if parent_view.view_id == *_vid{
									(*v).splitter = dragging_view.clone();
									reset_split_layout_div(&mut *v);
								}
							}
						}
						invalidate_view(&context, parent_view.clone());
					}else{
						invalidate(&context);
					}
				}
				else{
					let top_views = get_top_views();
					let find_view = find_view(mp.clone(), top_views);
					if M_TOUCH_MOVE_VIEW != -1 && M_TOUCH_MOVE_VIEW != find_view.view_id{
						let old_view = M_VIEW_MAP.lock().unwrap()[&M_TOUCH_MOVE_VIEW].clone();
						invalidate_view(&context, old_view.clone());
					}
					M_TOUCH_MOVE_VIEW = find_view.view_id;
					let cmp  = FCPoint{x:mp.x - client_x(find_view.clone()), y:mp.y - client_y(find_view.clone())};
					on_mouse_move(&context, find_view.clone(), cmp.clone(), 0, 0, 0);
				}
			}
		}
    }) as Box<dyn FnMut(_)>);
    canvas.add_event_listener_with_callback("mousemove", closure.as_ref().unchecked_ref()).unwrap();
    closure.forget();
}

/*
* Mouse pressed function
*/
pub fn mouse_down(context: &std::rc::Rc<web_sys::CanvasRenderingContext2d>, pressed: &std::rc::Rc<std::cell::Cell<bool>>, canvas: &web_sys::HtmlCanvasElement){
    let pressed = pressed.clone();
    let context = context.clone();
    let closure = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| {
        unsafe{
			if !M_IS_MOBILE{
				M_CANCEL_CLICK = false;
				let scale_factor_x = M_PAINT.lock().unwrap().scale_factor_x;
				let scale_factor_y = M_PAINT.lock().unwrap().scale_factor_y;
				M_TOUCH_DOWN_POINT = FCPoint{x:event.offset_x() as f32 / scale_factor_x as f32, y:event.offset_y() as f32 / scale_factor_y as f32};
				let top_views = get_top_views();
				let mut touch_down_view = find_view(M_TOUCH_DOWN_POINT.clone(), top_views);
				M_TOUCH_DOWN_VIEW = touch_down_view.view_id;
				let mut clicks = 1;
				/*if let Ok(duration) = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
					let newClickTime:i64 = duration.as_millis() as i64; 
					if newClickTime - M_LASTCLICKTIME < 250{
						M_IS_DOUBLECLICK = true;
						M_LASTCLICKTIME = 0;
						clicks = 2;
					}else{
						M_IS_DOUBLECLICK = true;
						M_LASTCLICKTIME = newClickTime;
					}
				}*/
				if M_TOUCH_DOWN_VIEW != -1 && is_view_enabled(touch_down_view.clone()){
					let last_focuesd_view = M_FOCUSED_VIEW;
					M_FOCUSED_VIEW = M_TOUCH_DOWN_VIEW;
					let cmp  = FCPoint{x:M_TOUCH_DOWN_POINT.x - client_x(touch_down_view.clone()), y:M_TOUCH_DOWN_POINT.y - client_y(touch_down_view.clone())};
					on_mouse_down(&context, touch_down_view.clone(), cmp.clone(), 1, clicks, 0);
					let window = web_sys::window().expect("should have a window in this context");
					let document = window.document().expect("window should have a document");
					let input: web_sys::HtmlInputElement = document.get_element_by_id("RUSTINPUTTEXT").unwrap().dyn_into().unwrap();
					let mut show_text_box =  false;
					if M_FOCUSED_VIEW != -1{
						let focused_view = M_VIEW_MAP.lock().unwrap()[&M_FOCUSED_VIEW].clone();
						if focused_view.view_type == "textbox"{
							if last_focuesd_view != -1{
								let mut focused_view2 = M_VIEW_MAP.lock().unwrap()[&last_focuesd_view].clone();
								if focused_view2.view_type == "textbox"{
									focused_view2.text = input.value();
									M_VIEW_MAP.lock().unwrap().insert(last_focuesd_view, focused_view2.clone());
									invalidate_view(&context, focused_view2.clone());
								}
							}
							input.style().set_property("display", "block").unwrap();
							let scale_factor_x = M_PAINT.lock().unwrap().scale_factor_x;
							let scale_factor_y = M_PAINT.lock().unwrap().scale_factor_y;
							let left_str = (client_x(focused_view.clone()) * scale_factor_x).to_string() + &"px";
							input.style().set_property("left", &left_str).unwrap();
							let top_str = (client_y(focused_view.clone()) * scale_factor_y).to_string() + &"px";
							input.style().set_property("top", &top_str).unwrap();
							let width_str = (focused_view.size.cx * scale_factor_x).to_string() + &"px";
							input.style().set_property("width", &width_str).unwrap();
							let height_str = (focused_view.size.cy * scale_factor_y).to_string() + &"px";
							input.style().set_property("height", &height_str).unwrap();
							input.style().set_property("background-color", &focused_view.back_color).unwrap();
							input.style().set_property("color", &focused_view.text_color).unwrap();
							let border_str = "1px solid ".to_string() + &focused_view.border_color;
							input.style().set_property("border", &border_str).unwrap();
							let str_split:Vec<&str> = focused_view.font.split(",").collect();
							let mut new_font = String::from("");
							let px_str = str_split[1];
							let mut num_font : f32 = px_str.parse::<f32>().unwrap();
							num_font = scale_factor_x.min(scale_factor_y) * num_font;
							if str_split[0] == "Default"{
								new_font = num_font.to_string() + "px Arial";
							}else{
								new_font = num_font.to_string() + "px " + str_split[0];
							}
							input.style().set_property("font", &new_font).unwrap();
							input.set_value(&focused_view.text);
							let event = web_sys::Event::new("click").unwrap();
							input.dispatch_event(&event).unwrap();
							show_text_box = true;
						}
					}
					if !show_text_box{
						if last_focuesd_view != -1{
							let mut focused_view2 = M_VIEW_MAP.lock().unwrap()[&last_focuesd_view].clone();
							if focused_view2.view_type == "textbox"{
								input.style().set_property("display", "none").unwrap();
								focused_view2.text = input.value();
								M_VIEW_MAP.lock().unwrap().insert(last_focuesd_view, focused_view2.clone());
								invalidate_view(&context, focused_view2.clone());								
							}
						}
					}
					if touch_down_view.allow_resize{
						touch_down_view.resize_point = get_resize_state(touch_down_view.clone(), cmp.clone());
						if touch_down_view.resize_point != -1{
							touch_down_view.start_rect = FCRect{left:touch_down_view.location.x, top:touch_down_view.location.y, right:touch_down_view.location.x + touch_down_view.size.cx,
								bottom:touch_down_view.location.y + touch_down_view.size.cy};
							M_VIEW_MAP.lock().unwrap().insert(touch_down_view.view_id, touch_down_view.clone());
						}
					}
				}
			}
        }
        pressed.set(true);
    }) as Box<dyn FnMut(_)>);
    canvas.add_event_listener_with_callback("mousedown", closure.as_ref().unchecked_ref()).unwrap();
    closure.forget();
}

/*
* Static global
*/
lazy_static! {
        pub static ref M_VIEW_MAP:Mutex<HashMap<i32,FCView>> = {
			let map:HashMap<i32,FCView> = HashMap::new();
			 Mutex::new(map)
        };
		pub static ref M_PARENT_VIEW_MAP:Mutex<HashMap<i32,i32>> = 
		{
			let map:HashMap<i32,i32> = HashMap::new();
			 Mutex::new(map)
		}; 
		pub static ref M_NONE_VIEW:Mutex<FCView> = {
			let view:FCView = FCView::new();
			 Mutex::new(view)
		};
		pub static ref M_PAINT:Mutex<FCPaint> = {
			let paint:FCPaint = FCPaint::new();
			 Mutex::new(paint)
		};
		
		pub static ref M_GRID_MAP:Mutex<HashMap<i32,FCGrid>> = {
			let grid_map:HashMap<i32,FCGrid> = HashMap::new();
			 Mutex::new(grid_map)
        };
        pub static ref M_CHART_MAP:Mutex<HashMap<i32,FCChart>> = {
			let chart_map:HashMap<i32,FCChart> = HashMap::new();
			 Mutex::new(chart_map)
        };
        pub static ref M_TAB_MAP:Mutex<HashMap<i32,FCTabView>> = {
			let tab_map:HashMap<i32,FCTabView> = HashMap::new();
			 Mutex::new(tab_map)
        };
        pub static ref M_LAYOUT_MAP:Mutex<HashMap<i32,FCLayoutDiv>> = {
			let layout_map:HashMap<i32,FCLayoutDiv> = HashMap::new();
			 Mutex::new(layout_map)
        };
        pub static ref M_SPLIT_MAP:Mutex<HashMap<i32,FCSplitLayoutDiv>> = {
			let split_map:HashMap<i32,FCSplitLayoutDiv> = HashMap::new();
			 Mutex::new(split_map)
        };
        pub static ref M_CHECK_BOX_MAP:Mutex<HashMap<i32,FCCheckBox>> = {
			let check_box_map:HashMap<i32,FCCheckBox> = HashMap::new();
			 Mutex::new(check_box_map)
        };
        pub static ref M_RADIO_BUTTON_MAP:Mutex<HashMap<i32,FCRadioButton>> = {
			let radio_button_map:HashMap<i32,FCRadioButton> = HashMap::new();
			 Mutex::new(radio_button_map)
        };
}

/*
* Redraw views
* context:Drawing context
* views:View Collection
* rect:Region
* has_rect:Is it an empty rectangle
*/
pub fn render_views(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, views:Vec<FCView>, rect:FCRect, has_rect:bool){
	let views_size = views.len();
	 for i in 0..views_size{
		let view = &views[i];
		let v_id = view.view_id;
		if !has_rect{
			let sub_views = get_sub_views(view.clone());
			let sub_views_size = sub_views.len();
		    if sub_views_size > 0 {
		        if sub_views_size > 0 {
			        render_views(context, sub_views, rect.clone(), false);
		        }
	        }
	        let mut change_view = M_VIEW_MAP.lock().unwrap()[&v_id].clone();
		    change_view.has_clip = false;
		    M_VIEW_MAP.lock().unwrap().insert(v_id, change_view);
		    continue;
		}
		if !view.top_most && is_paint_visible(view.clone()){
			let clx = client_x(view.clone());
			let cly = client_y(view.clone());
			let draw_rect = FCRect{left:0.0, top:0.0, right:view.size.cx, bottom:view.size.cy};
			let clip_rect = FCRect{left:clx, top:cly, right:clx + view.size.cx, bottom:cly + view.size.cy};
			let mut dest_rect = FCRect{left:0.0, top:0.0, right:0.0, bottom:0.0};
			if get_intersect_rect(&mut dest_rect, rect.clone(), clip_rect.clone()) > 0{
				M_PAINT.lock().unwrap().save(context);
			    M_PAINT.lock().unwrap().set_offset(context, 0.0, 0.0);
			    M_PAINT.lock().unwrap().set_clip(context, dest_rect.left, dest_rect.top, dest_rect.right, dest_rect.bottom);
			    
			    let mut change_view = M_VIEW_MAP.lock().unwrap()[&v_id].clone();
				change_view.has_clip = true;
				change_view.clip_rect = dest_rect.clone();
				M_VIEW_MAP.lock().unwrap().insert(v_id, change_view);
			    M_PAINT.lock().unwrap().set_offset(context, clx, cly);
			    on_paint(context, view.clone(), draw_rect.clone());
			    let sub_views = get_sub_views(view.clone());
				let sub_views_size = sub_views.len();
				if sub_views_size > 0 {
					render_views(context, sub_views, dest_rect.clone(), true);
				}
			    M_PAINT.lock().unwrap().set_offset(context, clx, cly);
			    on_paint_border(context, view.clone(), draw_rect.clone());
			    M_PAINT.lock().unwrap().restore(context);
			}else{
				let sub_views = get_sub_views(view.clone());
				let sub_views_size = sub_views.len();
				if sub_views_size > 0 {
					render_views(context, sub_views, rect.clone(), false);
				}
				let mut change_view = M_VIEW_MAP.lock().unwrap()[&v_id].clone();
				change_view.has_clip = false;
				M_VIEW_MAP.lock().unwrap().insert(v_id, change_view);
			}
		}
	}
	for i in 0..views_size{
		let view = &views[i];
		let v_id = view.view_id;
		if !has_rect{
		    continue;
		}
		if view.top_most && is_paint_visible(view.clone()) {
			let clx = client_x(view.clone());
			let cly = client_y(view.clone());
			let draw_rect = FCRect{left:0.0, top:0.0, right:view.size.cx, bottom:view.size.cy};
			let clip_rect = FCRect{left:clx, top:cly, right:clx + view.size.cx, bottom:cly + view.size.cy};
			let mut dest_rect = FCRect{left:0.0, top:0.0, right:0.0, bottom:0.0};
			if get_intersect_rect(&mut dest_rect, rect.clone(), clip_rect.clone()) > 0{
				M_PAINT.lock().unwrap().save(context);
			    M_PAINT.lock().unwrap().set_offset(context, 0.0, 0.0);
			    M_PAINT.lock().unwrap().set_clip(context, dest_rect.left, dest_rect.top, dest_rect.right, dest_rect.bottom);
			    
			    let mut change_view = M_VIEW_MAP.lock().unwrap()[&v_id].clone();
				change_view.has_clip = true;
				change_view.clip_rect = dest_rect.clone();
				M_VIEW_MAP.lock().unwrap().insert(v_id, change_view);
			    M_PAINT.lock().unwrap().set_offset(context, clx, cly);
			    on_paint(context, view.clone(), draw_rect.clone());
			    let sub_views = get_sub_views(view.clone());
				let sub_views_size = sub_views.len();
				if sub_views_size > 0 {
					render_views(context, sub_views, dest_rect.clone(), true);
				}
			    
			    M_PAINT.lock().unwrap().set_offset(context, clx, cly);
			    on_paint_border(context, view.clone(), draw_rect.clone());
			    M_PAINT.lock().unwrap().restore(context);
			}else{
				let sub_views = get_sub_views(view.clone());
				let sub_views_size = sub_views.len();
				if sub_views_size > 0 {
					render_views(context, sub_views, rect.clone(), false);
				}
				let mut change_view = M_VIEW_MAP.lock().unwrap()[&v_id].clone();
				change_view.has_clip = false;
				M_VIEW_MAP.lock().unwrap().insert(v_id, change_view);
			}
		}
	}
}

/*
* Find view based on coordinates
* mp:Coordinate
* views:View collection
*/
pub fn find_view(mp:FCPoint, views:Vec<FCView>)->FCView{
	let none_view = M_NONE_VIEW.lock().unwrap().clone();
	let views_size = views.len();
	for i in 0..views_size{
		let view = &views[views_size - i - 1];
		if view.visible && view.top_most {
			if contains_point(view.clone(), mp.clone()) {
			    if view.vscroll_is_visible && view.scroll_size > 0.0{
			        let clx = client_x(view.clone());
	                if mp.x >= clx + view.size.cx - view.scroll_size{
	                    return view.clone();
	                }
			    }
			    if view.hscroll_is_visible && view.scroll_size > 0.0{
			        let cly = client_y(view.clone());
	                if mp.y >= cly + view.size.cy - view.scroll_size{
	                    return view.clone();
	                }
			    }
			    let sub_views = get_sub_views(view.clone());
				let sub_views_size = sub_views.len();
				if sub_views_size > 0 {
					let sub_view = find_view(mp.clone(), sub_views);
					if sub_view.view_id != -1 {
						return sub_view.clone();
					}
				}
				return view.clone();
			}
		}
	}
	for i in 0..views_size{
		let view = &views[views_size - i - 1];
		if view.visible && !view.top_most {
			if contains_point(view.clone(), mp.clone()){
			    if view.hscroll_is_visible && view.scroll_size > 0.0{
			        let clx = client_x(view.clone());
	                if mp.x >= clx + view.size.cx - view.scroll_size{
	                    return view.clone();
	                }
			    }
			    if view.hscroll_is_visible && view.scroll_size > 0.0{
			        let cly = client_y(view.clone());
	                if mp.y >= cly + view.size.cy - view.scroll_size{
	                    return view.clone();
	                }
			    }
			    let sub_views = get_sub_views(view.clone());
				let sub_views_size = sub_views.len();
				if sub_views_size > 0 {
					let sub_view = find_view(mp.clone(), sub_views);
					if sub_view.view_id != -1 {
						return sub_view.clone();
					}
				}
				return view.clone();
			}
		}
	}
	return none_view;
}

/*
* Global refresh method
* context:Drawing context
*/
pub fn invalidate(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>){
	unsafe{
		let top_views2 = get_top_views();
		render_views(&context, top_views2, FCRect{left:0.0, top:0.0, right:M_CANVAS_WIDTH, bottom:M_CANVAS_HEIGHT}, true);
	}
}

/*
* Refresh view method
* context:Drawing context
* view:Target view
*/
pub fn invalidate_view(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, view:FCView){
	if is_paint_visible(view.clone()){
		let top_views2 = get_top_views();
		let cl_x = client_x(view.clone());
	    let cl_y = client_y(view.clone());
	    let draw_rect = FCRect{left:cl_x, top:cl_y, right:cl_x + view.size.cx, bottom:cl_y + view.size.cy};
		render_views(&context, top_views2, draw_rect, true);
	}
}

/*
* Redraw check button
* context:Drawing context
* check_box:CheckBox view
* clip_rect:Crop area
*/
pub fn draw_check_box(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, check_box:&mut FCCheckBox, clip_rect:FCRect){
	let width = check_box.view.size.cx;
	let height = check_box.view.size.cy;
    if check_box.view.text_color != "none" {
        let e_right = check_box.button_size.cx + 10.0;
        let mut e_rect = FCRect{left:1.0, top:(height - check_box.button_size.cy) / 2.0, right:check_box.button_size.cx + 1.0, bottom:(height + check_box.button_size.cy) / 2.0};
		if check_box.view.text.len() == 0{
			e_rect = FCRect{left:(width - check_box.button_size.cx) / 2.0, top:(height - check_box.button_size.cy) / 2.0, right:(width + check_box.button_size.cx) / 2.0, bottom:(height + check_box.button_size.cy) / 2.0};
		}
        M_PAINT.lock().unwrap().draw_rect(&context, check_box.view.text_color.clone(), 1.0, Vec::new(), e_rect.left, e_rect.top, e_rect.right, e_rect.bottom);
        if check_box.checked {
            e_rect.left += 2.0;
            e_rect.top += 2.0;
            e_rect.right -= 2.0;
            e_rect.bottom -= 2.0;
			M_PAINT.lock().unwrap().begin_path(&context);
			M_PAINT.lock().unwrap().add_line(&context, e_rect.left, e_rect.top + 8.0, e_rect.left + 6.0, e_rect.bottom);
			M_PAINT.lock().unwrap().add_line(&context, e_rect.left + 6.0, e_rect.bottom, e_rect.right - 1.0, e_rect.top);
			M_PAINT.lock().unwrap().draw_path(&context, check_box.view.text_color.clone(), 1.0, Vec::new());
			M_PAINT.lock().unwrap().close_path(&context);
        }
		if check_box.view.text.len() > 0{
			let t_size = M_PAINT.lock().unwrap().text_size(&context, check_box.view.text.clone(), check_box.view.font.clone());
			M_PAINT.lock().unwrap().draw_text(&context, check_box.view.text.clone(), check_box.view.text_color.clone(), check_box.view.font.clone(), e_right, height / 2.0 - t_size.cy / 2.0);
		}
    }
}

/*
* Redraw radio button
* context:Drawing context
* radio_button:Radio button view
* clip_rect:Crop area
*/
pub fn draw_radio_button(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, radio_button:&mut FCRadioButton, clip_rect:FCRect){
	let width = radio_button.view.size.cx;
	let height = radio_button.view.size.cy;
	if radio_button.view.text_color != "none" {
		let e_right = radio_button.button_size.cx + 10.0;
        let mut e_rect = FCRect{left:1.0, top:(height - radio_button.button_size.cy) / 2.0, right:radio_button.button_size.cx + 1.0, bottom:(height + radio_button.button_size.cy) / 2.0};
        M_PAINT.lock().unwrap().draw_ellipse(&context, radio_button.view.text_color.clone(), 1.0, Vec::new(), e_rect.left, e_rect.top, e_rect.right, e_rect.bottom);
        if radio_button.checked {
            e_rect.left += 2.0;
            e_rect.top += 2.0;
            e_rect.right -= 2.0;
            e_rect.bottom -= 2.0;
            M_PAINT.lock().unwrap().fill_ellipse(&context, radio_button.view.text_color.clone(), e_rect.left, e_rect.top, e_rect.right, e_rect.bottom);
        }
		let t_size = M_PAINT.lock().unwrap().text_size(&context, radio_button.view.text.clone(), radio_button.view.font.clone());
        M_PAINT.lock().unwrap().draw_text(&context, radio_button.view.text.clone(), radio_button.view.text_color.clone(), radio_button.view.font.clone(), e_right, height / 2.0 - t_size.cy / 2.0);
	}
}

/*
* Redraw button
* context:Drawing context
* button:Button view
* clip_rect:Crop area
*/
pub fn draw_button(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, button:&mut FCView, clip_rect:FCRect){
	unsafe{
		if M_TOUCH_DOWN_VIEW == button.view_id && button.pushed_color != "none"{
			M_PAINT.lock().unwrap().fill_round_rect(&context, button.pushed_color.clone(), 0.0, 0.0, button.size.cx, button.size.cy, button.corner_radius);
		}else if M_TOUCH_MOVE_VIEW == button.view_id && button.hovered_color != "none"{
			M_PAINT.lock().unwrap().fill_round_rect(&context, button.hovered_color.clone(), 0.0, 0.0, button.size.cx, button.size.cy, button.corner_radius);
		}
		else if button.back_color != "none"{
			M_PAINT.lock().unwrap().fill_round_rect(&context, button.back_color.clone(), 0.0, 0.0, button.size.cx, button.size.cy, button.corner_radius);
		}
		if button.text_color != "none"{
			let t_size = M_PAINT.lock().unwrap().text_size(&context, button.text.clone(), button.font.clone());
			M_PAINT.lock().unwrap().draw_text(&context, button.text.clone(), button.text_color.clone(), button.font.clone(), (button.size.cx - t_size.cx) / 2.0, button.size.cy / 2.0 - t_size.cy / 2.0);
		}
		if button.border_color != "none"{
			M_PAINT.lock().unwrap().draw_round_rect(&context, button.border_color.clone(), button.border_width, Vec::new(), 0.0, 0.0, button.size.cx, button.size.cy, button.corner_radius);
		}
	}
}

/*
*Click on the check button
*check_box: view
*mp: coordinates
*/
pub fn click_check_box(check_box:&mut FCCheckBox, mp:FCPoint){
	check_box.checked = !check_box.checked;
}

/*
*Click on the radio button
*radio_button: view
*mp: coordinates
*/
pub fn click_radio_button(radio_button:&mut FCRadioButton, mp:FCPoint){
	radio_button.checked = true;
}

/*
*Redraw div edges
*context: Drawing context
*div: view
*clip_rect: Crop region
*/
pub fn draw_div_border(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, div:&mut FCView, clip_rect:FCRect){
	if div.border_color != "none"{
        M_PAINT.lock().unwrap().draw_round_rect(&context, div.border_color.clone(), div.border_width, Vec::new(), 0.0, 0.0, div.size.cx, div.size.cy, div.corner_radius);
    }
}

/*
*Redraw div
*context: Drawing context
*div: view
*clip_rect: Crop region
*/
pub fn draw_div(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, div:&mut FCView, clip_rect:FCRect){
	if div.back_color != "none"{
        M_PAINT.lock().unwrap().fill_round_rect(&context, div.back_color.clone(), 0.0, 0.0, div.size.cx, div.size.cy, div.corner_radius);
    }
}

/*
* Obtain the width of the content
* div:view
*/
pub fn get_div_content_width(div:&mut FCView)->f32{
	let mut c_width : f32 = 0.0;
	let sub_views = get_sub_views(div.clone());
	if sub_views.len() > 0{
		for i in 0..sub_views.len(){
			let sub_view = &sub_views[i];
			if sub_view.visible {
			    if c_width < sub_view.location.x + sub_view.size.cx{
			        c_width = sub_view.location.x + sub_view.size.cx;
			    }
		    }
		}
	}
	return c_width;
}

/*
* Obtain the height of the content
* div:view
*/
pub fn get_div_content_height(div:&mut FCView)->f32{
	let mut c_height : f32 = 0.0;
	let sub_views = get_sub_views(div.clone());
	if sub_views.len() > 0{
		for i in 0..sub_views.len(){
			let sub_view = &sub_views[i];
			if sub_view.visible {
			    if c_height < sub_view.location.y + sub_view.size.cy{
			        c_height = sub_view.location.y + sub_view.size.cy;
			    }
		    }
		}
	}
	return c_height;
}

/*
* Mouse wheel method for div
* div:View
* delta:Wheel delta
*/
pub fn touch_wheel_div(div:&mut FCView, delta:i32){
	let mut old_scroll_v = div.scroll_v;
    if delta > 0 {
	    old_scroll_v = old_scroll_v - 20.0;
    } else if delta < 0 {
	    old_scroll_v = old_scroll_v + 20.0;
    }
    let content_height = get_div_content_height(div);
    if content_height < div.size.cy {
        div.scroll_v = 0.0;
    } else {
        if old_scroll_v < 0.0 {
	        old_scroll_v = 0.0;
	    } else if old_scroll_v > content_height - div.size.cy {
		    old_scroll_v = content_height - div.size.cy;
        }
        div.scroll_v = old_scroll_v;
    }
}

/*
*Draw scroll bar
*context: Drawing context
*div: view
*clip_rect: Crop region
*/
pub fn draw_div_scroll_bar(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, div:&mut FCView, clip_rect:FCRect){
	div.hscroll_is_visible = false;
	div.vscroll_is_visible = false;
	if div.show_hscrollbar {
		let content_width = get_div_content_width(div);
		if content_width > 0.0 && content_width > div.size.cx {
			let s_left = div.scroll_h / content_width * div.size.cx;
			let mut s_right = (div.scroll_h + div.size.cx) / content_width * div.size.cx;
			if s_right - s_left < div.scroll_size {
				s_right = s_left + div.scroll_size;
			}
			M_PAINT.lock().unwrap().fill_rect(&context, div.scroll_barcolor.clone(), s_left, div.size.cy - div.scroll_size, s_right, div.size.cy);
			div.hscroll_is_visible = true;
		}
	}
	if div.show_vscrollbar{
	    let content_height = get_div_content_height(div);		
		if content_height > 0.0 && content_height > div.size.cy {
			let s_top = div.scroll_v / content_height * div.size.cy;
			let mut s_bottom  = s_top + (div.size.cy / content_height * div.size.cy);
			if s_bottom  - s_top < div.scroll_size {
				s_bottom  = s_top + div.scroll_size;
			}
			M_PAINT.lock().unwrap().fill_rect(&context, div.scroll_barcolor.clone(), div.size.cx - div.scroll_size, s_top, div.size.cx, s_bottom );
			div.vscroll_is_visible = true;
		}
	}
}

/*
* Touch up method for div
* div: View
* first_touch:Is it first touch
* first_point:Point of first touch
* second_touch:Is it second touch
* second_point:Point of second touch
*/
pub fn touch_up_div(div:&mut FCView, first_touch:bool, first_point:FCPoint, second_touch:bool, second_point:FCPoint){
	div.down_scroll_hbutton = false;
	div.down_scroll_vbutton = false;
}

/*
* Touch move method for div
* div: View
* first_touch:Is it first touch
* first_point:Point of first touch
* second_touch:Is it second touch
* second_point:Point of second touch
*/
pub fn touch_move_div(div:&mut FCView, first_touch:bool, first_point:FCPoint, second_touch:bool, second_point:FCPoint){
	if first_touch {
		let mp = first_point.clone();
		if div.show_hscrollbar || div.show_vscrollbar {
			if div.down_scroll_hbutton {
				let content_width = get_div_content_width(div);
				let sub_x = (mp.x - div.start_point.x) / div.size.cx * content_width;
				let mut new_scrollh = div.start_scroll_h + sub_x;
				if new_scrollh < 0.0 {
					new_scrollh = 0.0;
				} else if new_scrollh > content_width - div.size.cx {
					new_scrollh = content_width - div.size.cx;
				}
				div.scroll_h = new_scrollh;
				unsafe{
					M_CANCEL_CLICK = true;
				}
				return;

			} else if div.down_scroll_vbutton {
				let content_height = get_div_content_height(div);
				let sub_y = (mp.y - div.start_point.y) / div.size.cy * content_height;
				let mut new_scroll_v = div.start_scroll_v + sub_y;
				if new_scroll_v < 0.0 {
					new_scroll_v = 0.0;
				} else if new_scroll_v > content_height - div.size.cy {
					new_scroll_v = content_height - div.size.cy;
				}
				div.scroll_v = new_scroll_v;
				unsafe{
					M_CANCEL_CLICK = true;
				}
				return;
			}
		}
		if div.allow_drag_scroll {
			let content_width = get_div_content_width(div);
			if content_width > div.size.cx {
				let sub_x = div.start_point.x - mp.x;
				let mut new_scrollh = div.start_scroll_h + sub_x;
				if new_scrollh < 0.0 {
					new_scrollh = 0.0;
				} else if new_scrollh > content_width - div.size.cx {
					new_scrollh = content_width - div.size.cx;
				}
				div.scroll_h = new_scrollh;
				if sub_x.abs() > 5.0{
					unsafe{
						M_CANCEL_CLICK = true;
				    }
				}
			}
			let content_height = get_div_content_height(div);
			if content_height > div.size.cy {
				let sub_y = div.start_point.y - mp.y;
				let mut new_scroll_v = div.start_scroll_v + sub_y;
				if new_scroll_v < 0.0 {
					new_scroll_v = 0.0;
				} else if new_scroll_v > content_height - div.size.cy {
					new_scroll_v = content_height - div.size.cy;
				}
				div.scroll_v = new_scroll_v;
				if sub_y.abs() > 5.0{
					unsafe{
						M_CANCEL_CLICK = true;
				    }
				}
			}
		}
	}
}

/*
* Touch down method for div
* div: View
* first_touch:Is it first touch
* first_point:Point of first touch
* second_touch:Is it second touch
* second_point:Point of second touch
*/
pub fn touch_down_div(div:&mut FCView, first_touch:bool, first_point:FCPoint, second_touch:bool, second_point:FCPoint){
	let mp = first_point.clone();
	div.start_point = mp.clone();
	div.down_scroll_hbutton = false;
	div.down_scroll_vbutton = false;
	if div.show_hscrollbar {
		let content_width = get_div_content_width(div);
		if content_width > 0.0 && content_width > div.size.cx {
		    let s_left = div.scroll_h / content_width * div.size.cx;
			let mut s_right = (div.scroll_h + div.size.cx) / content_width * div.size.cx;
			if s_right - s_left < div.scroll_size {
				s_right = s_left + div.scroll_size;
			}
			if mp.x >= s_left && mp.x <= s_right && mp.y >= div.size.cy - div.scroll_size && mp.y <= div.size.cy {
				div.down_scroll_hbutton = true;
				div.start_scroll_h = div.scroll_h;
				return;
			}
		}
	}
	if div.show_vscrollbar {
	    let content_height = get_div_content_height(div);
		if content_height > 0.0 && content_height > div.size.cy {
			let s_top = div.scroll_v / content_height * div.size.cy;
			let mut s_bottom  = (div.scroll_v + div.size.cy) / content_height * div.size.cy;
			if s_bottom  - s_top < div.scroll_size {
				s_bottom  = s_top + div.scroll_size;
			}
			if mp.x >= div.size.cx - div.scroll_size && mp.x <= div.size.cx && mp.y >= s_top && mp.y <= s_bottom  {
				div.down_scroll_vbutton = true;
				div.start_scroll_v = div.scroll_v;
				return;
			}
		}
	}
	if div.allow_drag_scroll {
		div.start_scroll_h = div.scroll_h;
		div.start_scroll_v = div.scroll_v;
	}
}

/*
* Update the layout of the page
* tab_view:TabView
* tab_page:TabPage
* left:Left
* top:Top
* width:Width
* height:Height
* tw:The width of the header button
* th:The height of the header button
*/
pub fn updata_page_layout(tab_view:&mut FCTabView, tab_page:&mut FCTabPage, left:f32, top:f32, width:f32, height:f32, tw:f32, th:f32){
	let mut new_bounds = FCRect{left:0.0, top:0.0, right:0.0, bottom:0.0};
	if tab_view.layout == "bottom" {
		new_bounds.left = 0.0;
		new_bounds.top = 0.0;
		new_bounds.right = width;
		new_bounds.bottom = height - th;
		tab_page.header_button.location = FCPoint{x:left, y:height - th};
	}else if tab_view.layout == "left" {
		new_bounds.left = tw;
		new_bounds.top = 0.0;
		new_bounds.right = width;
		new_bounds.bottom = height;
		tab_page.header_button.location = FCPoint{x:0.0, y:top};
	}else if tab_view.layout == "right" {
		new_bounds.left = 0.0;
		new_bounds.top = 0.0;
		new_bounds.right = width - tw;
		new_bounds.bottom = height;
		tab_page.header_button.location = FCPoint{x:width - tw, y:top};
	}else if tab_view.layout == "top" {
		new_bounds.left = 0.0;
		new_bounds.top = th;
		new_bounds.right = width;
		new_bounds.bottom = height;
		tab_page.header_button.location = FCPoint{x:left, y:0.0};
	}
	tab_page.view.location = FCPoint{x:new_bounds.left, y:new_bounds.top};
	tab_page.view.size = FCSize{cx:new_bounds.right - new_bounds.left, cy:new_bounds.bottom - new_bounds.top};
}

/*
* Update the layout of multiple page folders
* tab_view:TabView
*/
pub fn update_tab_layout(tab_view:&mut FCTabView){
	let width = tab_view.view.size.cx;
	let height = tab_view.view.size.cy;
	let mut left :f32 = 0.0;
	let mut top : f32 = 0.0;
	for i in 0..tab_view.tab_pages.len(){
		let mut tp = tab_view.tab_pages[i].clone();
		let header_button = tp.header_button.clone();
		if header_button.visible {
			let tw = header_button.size.cx;
			let th = header_button.size.cy;
			updata_page_layout(tab_view, &mut tp, left, top, width, height, tw, th);
			left = left + tw;
			top = top + th;
		}else{
			tp.view.visible = false;
		}
		M_VIEW_MAP.lock().unwrap().insert(tp.view.view_id, tp.view.clone());
		M_VIEW_MAP.lock().unwrap().insert(tp.header_button.view_id, tp.header_button.clone());
	}
}

/*
* Redraw tabview
* context:Drawing context
* tab_view:TabView
* clip_rect:Crop area
*/
pub fn draw_tabview_border(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, tab_view:&mut FCTabView, clip_rect:FCRect){
	if tab_view.under_line_color != "none" {
        for i in 0..tab_view.tab_pages.len(){
	        let tp = tab_view.tab_pages[i].clone();
	        if tp.view.visible {
	            let header_button = tp.header_button;
	            let mut location = FCPoint{x:header_button.location.x, y:header_button.location.y};
	            let size = header_button.size;
	            if tab_view.use_animation {
					location.x = tab_view.under_point.x;
                    location.y = tab_view.under_point.y;
                }
	            if tab_view.layout == "bottom" {
	                M_PAINT.lock().unwrap().fill_rect(&context, tab_view.under_line_color.clone(), location.x, location.y, location.x + size.cx, location.y + tab_view.under_line_size);
                }else if tab_view.layout == "left" {
                    M_PAINT.lock().unwrap().fill_rect(&context, tab_view.under_line_color.clone(), location.x + size.cx - tab_view.under_line_size, location.y, location.x + size.cx, location.y + size.cy);
                }else if tab_view.layout == "top" {
                    M_PAINT.lock().unwrap().fill_rect(&context, tab_view.under_line_color.clone(), location.x, location.y + size.cy - tab_view.under_line_size, location.x + size.cx, location.y + size.cy);
                }
                else if tab_view.layout == "right" {
                    M_PAINT.lock().unwrap().fill_rect(&context, tab_view.under_line_color.clone(), location.x, location.y, location.x + tab_view.under_line_size, location.y + size.cy);
                }
	            break;
	        }
        }
    }
}

/*
* Reset layout layer
* layout:LayoutDiv
*/
pub fn reset_layout_div(layout:&mut FCLayoutDiv)->bool{
	let mut reset:bool = false;
    let padding = layout.view.padding.clone();
    let mut v_pos:i32 = 0;
    let mut left = padding.left;
    let mut top = padding.top;
    let width = layout.view.size.cx - padding.left - padding.right;
    let height = layout.view.size.cy - padding.top - padding.bottom;
    let sub_views = get_sub_views(layout.view.clone());
    for i in 0..sub_views.len(){
        let mut view = (&sub_views[i]).clone();
        if view.visible{
            let size = view.size.clone();
            let margin = view.margin.clone();
            let c_left = view.location.x;
            let c_top = view.location.y;
            let c_width = size.cx;
            let c_height = size.cy;
            let mut n_left = c_left;
            let mut n_top = c_top;
            let mut n_width = c_width;
            let mut n_height = c_height;
            if layout.layout_style == "bottomtotop"{
                if i == 0{
                    top = height - padding.top;
                }
                let mut l_width:f32 = 0.0;
                if layout.auto_wrap{
                    l_width = size.cx;
                    let l_top = top - margin.top - c_height - margin.bottom;
                    if l_top < padding.top{
                        if v_pos != 0{
                            left += c_width + margin.left;
                        }
                        top = height - padding.top;
                    }
                }
                else{
                    l_width = width - margin.left - margin.right;
                }
                top -= c_height + margin.bottom;
                n_left = left + margin.left;
                n_width = l_width;
                n_top = top;
            }else if layout.layout_style == "lefttoright"{
                let mut l_height:f32 = 0.0;
                if layout.auto_wrap{
                    l_height = size.cy;
                    let l_right = left + margin.left + c_width + margin.right;
                    if l_right > width{
                        left = padding.left;
                        if v_pos != 0{
                            top += c_height + margin.top;
                        }
                    }
                }
                else{
                    l_height = height - margin.top - margin.bottom;
                }
                left += margin.left;
                n_left = left;
                n_top = top + margin.top;
                n_height = l_height;
                left += c_width + margin.right;
            }else if layout.layout_style == "righttoleft"{
                if i == 0{
                    left = width - padding.left;
                }
                let mut l_height:f32 = 0.0;
                if layout.auto_wrap{
                    l_height = size.cy;
                    let l_left = left - margin.left - c_width - margin.right;
                    if l_left < padding.left{
                        left = width - padding.left;
                        if v_pos != 0 {
                            top += c_height + margin.top;
                        }
                    }
                }
                else{
                    l_height = height - margin.top - margin.bottom;
                }
                left -= c_width + margin.left;
                n_left = left;
                n_top = top + margin.top;
                n_height = l_height;
            }else if layout.layout_style == "toptobottom"{
                let mut l_width:f32 = 0.0;
                if layout.auto_wrap{
                    l_width = size.cx;
                    let l_bottom = top + margin.top + c_height + margin.bottom;
                    if l_bottom > height{
                        if v_pos != 0{
                            left += c_width + margin.left + margin.right;
                        }
                        top = padding.top;
                    }
                }
                else{
                    l_width = width - margin.left - margin.right;
                }
                top += margin.top;
                n_top = top;
                n_left = left + margin.left;
                n_width = l_width;
                top += c_height + margin.bottom;
            }
            if c_left != n_left || c_top != n_top || c_width != n_width || c_height != n_height{
                view.location = FCPoint{x:n_left, y:n_top};
                view.size = FCSize{cx:n_width, cy:n_height};
				M_VIEW_MAP.lock().unwrap().insert(view.view_id, view.clone());
                reset = true;
            }
            v_pos = v_pos + 1;
        }
    }
    return reset;
}

/*
* Reset the layout of split lines
* split:SplitLayoutDiv
*/
pub fn reset_split_layout_div(split:&mut FCSplitLayoutDiv)->bool{
	let mut reset : bool = false;
    let mut split_rect = FCRect{left:0.0, top:0.0, right:0.0, bottom:0.0};
    let width = split.view.size.cx;
    let height = split.view.size.cy;
    let mut f_rect = FCRect{left:0.0, top:0.0, right:0.0, bottom:0.0};
    let mut s_rect = FCRect{left:0.0, top:0.0, right:0.0, bottom:0.0};
    let mut splitter_size = FCSize{cx:0.0, cy:0.0};
    if split.splitter.visible{
        splitter_size.cx = split.splitter.size.cx;
        splitter_size.cy = split.splitter.size.cy;
    }
    let layout_style = split.layout_style.clone();
    if layout_style == "bottomtotop"{
        if split.split_mode == "absolutesize" || split.old_size.cy == 0.0{
            split_rect.left = 0.0;
            split_rect.top = height - (split.old_size.cy - split.splitter.location.y);
            split_rect.right = width;
            split_rect.bottom = split_rect.top + splitter_size.cy;
        }
        else if split.split_mode == "percentsize"{
            split_rect.left = 0.0;
            if split.split_percent == -1.0{
                split.split_percent = split.splitter.location.y / split.old_size.cy;
            }
            split_rect.top = height * split.split_percent;
            split_rect.right = width;
            split_rect.bottom = split_rect.top + splitter_size.cy;
        }
        f_rect.left = 0.0;
        f_rect.top = split_rect.bottom;
        f_rect.right = width;
        f_rect.bottom = height;
        s_rect.left = 0.0;
        s_rect.top = 0.0;
        s_rect.right = width;
        s_rect.bottom = split_rect.top;
    }
    else if layout_style == "lefttoright"{
        if split.split_mode == "absolutesize" || split.old_size.cx == 0.0{
            split_rect.left = split.splitter.location.x;
            split_rect.top = 0.0;
            split_rect.right = split_rect.left + splitter_size.cx;
            split_rect.bottom = height;
        }
        else if split.split_mode == "percentsize"{
            if split.split_percent == -1.0{
                split.split_percent = split.splitter.location.x / split.old_size.cx;
            }
            split_rect.left = width * split.split_percent;
            split_rect.top = 0.0;
            split_rect.right = split_rect.left + splitter_size.cx;
            split_rect.bottom = height;
        }
        f_rect.left = 0.0;
        f_rect.top = 0.0;
        f_rect.right = split_rect.left;
        f_rect.bottom = height;
        s_rect.left = split_rect.right;
        s_rect.top = 0.0;
        s_rect.right = width;
        s_rect.bottom = height;
    }
    else if layout_style == "righttoleft"{
        if split.split_mode == "absolutesize" || split.old_size.cx == 0.0{
            split_rect.left = width - (split.old_size.cx - split.splitter.location.x);
            split_rect.top = 0.0;
            split_rect.right = split_rect.left + splitter_size.cx;
            split_rect.bottom = height;
        }
        else if split.split_mode == "percentsize"{
            if split.split_percent == -1.0{
                split.split_percent = split.splitter.location.x / split.old_size.cx;
            }
            split_rect.left = width * split.split_percent;
            split_rect.top = 0.0;
            split_rect.right = split_rect.left + splitter_size.cx;
            split_rect.bottom = height;
        }
        f_rect.left = split_rect.right;
        f_rect.top = 0.0;
        f_rect.right = width;
        f_rect.bottom = height;
        s_rect.left = 0.0;
        s_rect.top = 0.0;
        s_rect.right = split_rect.left;
        s_rect.bottom = height;
    }
    else if layout_style == "toptobottom"{
        if split.split_mode == "absolutesize" || split.old_size.cy == 0.0{
            split_rect.left = 0.0;
            split_rect.top = split.splitter.location.y;
            split_rect.right = width;
            split_rect.bottom = split_rect.top + splitter_size.cy;
        }
        else if split.split_mode == "percentsize"{
            split_rect.left = 0.0;
            if split.split_percent == -1.0{
                split.split_percent = split.splitter.location.y / split.old_size.cy;
            }
            split_rect.top = height * split.split_percent;
            split_rect.right = width;
            split_rect.bottom = split_rect.top + splitter_size.cy;
        }
        f_rect.left = 0.0;
        f_rect.top = 0.0;
        f_rect.right = width;
        f_rect.bottom = split_rect.top;
        s_rect.left = 0.0;
        s_rect.top = split_rect.bottom;
        s_rect.right = width;
        s_rect.bottom = height;
    }
    if split.splitter.visible{
        let sp_rect = FCRect{left:split.splitter.location.x,  top:split.splitter.location.y, right:split.splitter.location.x + split.splitter.size.cx, bottom:split.splitter.location.y + split.splitter.size.cy};
        if sp_rect.left != split_rect.left || sp_rect.top != split_rect.top || sp_rect.right != split_rect.right || sp_rect.bottom != split_rect.bottom{
            split.splitter.location = FCPoint{x:split_rect.left, y:split_rect.top};
            split.splitter.size = FCSize{cx:split_rect.right - split_rect.left, cy:split_rect.bottom - split_rect.top};
            M_VIEW_MAP.lock().unwrap().insert(split.splitter.view_id, split.splitter.clone());
            reset = true;
        }
    }
    let fc_rect = FCRect{left:split.first_view.location.x,  top:split.first_view.location.y, right:split.first_view.location.x + split.first_view.size.cx, bottom:split.first_view.location.y + split.first_view.size.cy};
    if fc_rect.left != f_rect.left || fc_rect.top != f_rect.top || fc_rect.right != f_rect.right || fc_rect.bottom != f_rect.bottom{
        reset = true;
        split.first_view.location = FCPoint{x:f_rect.left, y:f_rect.top};
        split.first_view.size = FCSize{cx:f_rect.right - f_rect.left, cy:f_rect.bottom - f_rect.top};
        M_VIEW_MAP.lock().unwrap().insert(split.first_view.view_id, split.first_view.clone());
    }
    let sc_rect = FCRect{left:split.second_view.location.x,  top:split.second_view.location.y, right:split.second_view.location.x + split.second_view.size.cx, bottom:split.second_view.location.y + split.second_view.size.cy};
    if sc_rect.left != s_rect.left || sc_rect.top != s_rect.top || sc_rect.right != s_rect.right || sc_rect.bottom != s_rect.bottom{
        reset = true;
        split.second_view.location = FCPoint{x:s_rect.left, y:s_rect.top};
        split.second_view.size = FCSize{cx:s_rect.right - s_rect.left, cy:s_rect.bottom - s_rect.top};
        M_VIEW_MAP.lock().unwrap().insert(split.second_view.view_id, split.second_view.clone());
    }
    split.old_size = FCSize{cx:width, cy:height};
    return reset;
}

/*
* Obtain the width of the content
* grid:Grid
*/
pub fn get_grid_content_width(grid:&mut FCGrid)->f32{
	let mut c_width:f32 = 0.0;
	for i in 0..grid.columns.len(){
		let grid_column = (&grid.columns[i]).clone();
		if grid_column.visible{
			c_width = c_width + grid_column.width;
		}
	}
	return c_width;
}

/*
* Obtain the height of the content
* grid:Grid
*/
pub fn get_grid_content_height(grid:&mut FCGrid)->f32{
	let mut c_height:f32 = 0.0;
	for i in 0..grid.rows.len(){
		let grid_row = (&grid.rows[i]).clone();
		if grid_row.visible {
			c_height = c_height + grid.row_height;
		}
	}
	return c_height;
}

/*
* Draw a scroll bar for the table
* context:Drawing context
* grid:Grid
* clip_rect:Crop area
*/
pub fn draw_grid_scroll_bar(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, grid:&mut FCGrid, clip_rect:FCRect){
	grid.view.hscroll_is_visible = false;
	grid.view.vscroll_is_visible = false;
	if grid.header_height > 0.0 {
		let mut c_left = -grid.view.scroll_h;
		for i in 0..grid.columns.len(){
			let grid_column = (&grid.columns[i]).clone();
			if grid_column.visible {
				if !grid_column.frozen {
				    draw_grid_column(&context, grid, grid_column.clone(), c_left, 0.0, c_left + grid_column.width, grid.header_height);
				}
				c_left = c_left + grid_column.width;
			}
		}
		c_left = 0.0;
		for i in 0..grid.columns.len(){
			let grid_column = (&grid.columns[i]).clone();
			if grid_column.visible {
				if grid_column.frozen {
				    draw_grid_column(&context, grid, grid_column.clone(), c_left, 0.0, c_left + grid_column.width, grid.header_height);
				}
				c_left = c_left + grid_column.width;
			}
		}
	}
	if grid.view.show_hscrollbar {
		let content_width = get_grid_content_width(grid);
		if content_width > 0.0 && content_width > grid.view.size.cx {
			let s_left = grid.view.scroll_h / content_width * grid.view.size.cx;
			let mut s_right = (grid.view.scroll_h + grid.view.size.cx) / content_width * grid.view.size.cx;
			if s_right - s_left < grid.view.scroll_size {
				s_right = s_left + grid.view.scroll_size;
			}
			M_PAINT.lock().unwrap().fill_rect(&context, grid.view.scroll_barcolor.clone(), s_left, grid.view.size.cy - grid.view.scroll_size, s_right, grid.view.size.cy);
			grid.view.hscroll_is_visible = true;
		}
	}
	if grid.view.show_vscrollbar{
	    let content_height = get_grid_content_height(grid);
		if content_height > 0.0 && content_height > grid.view.size.cy - grid.header_height {
			let s_top = grid.header_height + grid.view.scroll_v / content_height * (grid.view.size.cy - grid.header_height - grid.view.scroll_size);
			let mut s_bottom  = s_top + ((grid.view.size.cy - grid.header_height - grid.view.scroll_size)) / content_height * (grid.view.size.cy - grid.header_height - grid.view.scroll_size);
			if s_bottom  - s_top < grid.view.scroll_size {
				s_bottom  = s_top + grid.view.scroll_size;
			}
			M_PAINT.lock().unwrap().fill_rect(&context, grid.view.scroll_barcolor.clone(), grid.view.size.cx - grid.view.scroll_size, s_top, grid.view.size.cx, s_bottom );
			grid.view.vscroll_is_visible = false;
		}
	}
}

/*
* Draw grid cell
* context:Drawing context
* grid:Grid
* row:Row
* column:Column
* cell:Cell
* left:Left
* top:Top
* right:Right
* bottom:Bottom
*/
pub fn draw_grid_cell(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, grid:&mut FCGrid, row:FCGridRow, column:FCGridColumn, cell:FCGridCell, left:f32, top:f32, right:f32, bottom:f32){
	if cell.back_color != "none" {
		M_PAINT.lock().unwrap().fill_rect(&context, cell.back_color.clone(), left, top, right, bottom);
	}
	if row.selected{
		if grid.selected_row_color != "none"{
			M_PAINT.lock().unwrap().fill_rect(&context, grid.selected_row_color.clone(), left, top, right, bottom);
		}
	}
	if cell.border_color != "none" {
		M_PAINT.lock().unwrap().draw_rect(&context, cell.border_color.clone(), 1.0, Vec::new(), left, top, right, bottom);
	}
	if cell.value.len() > 0 {
		let t_size = M_PAINT.lock().unwrap().text_size(&context, cell.value.clone(), cell.font.clone());
		if t_size.cx > column.width{
			M_PAINT.lock().unwrap().draw_text_auto_ellipsis(&context, cell.value.clone(), cell.text_color.clone(), cell.font.clone(), left + 2.0, top + grid.row_height / 2.0 - t_size.cy / 2.0, left + 2.0 + column.width, top + grid.row_height / 2.0 - t_size.cy / 2.0);
		} else {
			M_PAINT.lock().unwrap().draw_text(&context, cell.value.clone(), cell.text_color.clone(), cell.font.clone(), left + 2.0, top + grid.row_height / 2.0 - t_size.cy / 2.0);
		}
	}
}

/*
* Draw grid column
* context:Drawing context
* grid:Grid
* column:Column
* left:Left
* top:Top
* right:Right
* bottom:Bottom
*/
pub fn draw_grid_column(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, grid:&mut FCGrid, column:FCGridColumn, left:f32, top:f32, right:f32, bottom:f32){
	let t_size = M_PAINT.lock().unwrap().text_size(&context, column.text.clone(), column.font.clone());
	if column.back_color != "none" {
		M_PAINT.lock().unwrap().fill_rect(&context, column.back_color.clone(), left, top, right, bottom);
	}
	if column.border_color != "none" {
		M_PAINT.lock().unwrap().draw_rect(&context, column.border_color.clone(), 1.0, Vec::new(), left, top, right, bottom);
	}
	M_PAINT.lock().unwrap().draw_text(&context, column.text.clone(), column.text_color.clone(), column.font.clone(), left + (column.width - t_size.cx) / 2.0, top + grid.header_height / 2.0 - t_size.cy / 2.0);
}

/*
* Draw grid
* context:Drawing context
* grid:Grid
* clipRect:Crop area
*/
pub fn draw_grid(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, grid:&mut FCGrid, clip_rect:FCRect){
	let mut c_top = -grid.view.scroll_v + grid.header_height;
	let mut col_left = 0.0;
	for i in 0..grid.columns.len(){
		let mut grid_column = (&grid.columns[i]).clone();
		let col_rect= FCRect{left:col_left, top:0.0, right:col_left + grid_column.width, bottom:grid.header_height};
		grid_column.bounds = col_rect;
		grid_column.index = i as i32;
		col_left = col_left + grid_column.width;
		grid.columns[i] = grid_column;
	}
	for i in 0..grid.rows.len(){
		let row = (&grid.rows[i]).clone();
		if row.visible{
			let r_top = c_top;
			let r_bottom = c_top + grid.row_height;
			if r_bottom >= 0.0 && c_top <= grid.view.size.cy {
				for j in 0..row.cells.len(){
					let cell = (&row.cells[j]).clone();
					let grid_column = (&grid.columns[j]).clone();
					if grid_column.visible{
						if !grid_column.frozen {
							let mut cell_width = grid_column.width;
							let col_span = cell.col_span;
							if col_span > 1 {
								for n in 1..col_span{
									let span_column = (&grid.columns[(grid_column.index + n) as usize]).clone();
									if span_column.visible {
										cell_width = cell_width + span_column.width;
									}
								}
							}
							let mut cell_height = grid.row_height;
							let row_span = cell.row_span;
							if row_span > 1 {
								for n in 1..row_span{
									let span_row = (&grid.rows[i + n as usize]).clone();
									if span_row.visible {
										cell_height = cell_height + grid.row_height;
									}
								}
							}
							let c_rect = FCRect{left:grid_column.bounds.left - grid.view.scroll_h, top:r_top, right:grid_column.bounds.left + cell_width - grid.view.scroll_h, bottom:r_top + cell_height};
							if c_rect.right >= 0.0 && c_rect.left < grid.view.size.cx {
							    draw_grid_cell(&context, grid, row.clone(), grid_column.clone(), cell.clone(), c_rect.left, c_rect.top, c_rect.right, c_rect.bottom);
							}
						}
					}
				}
			}
			if r_bottom >= 0.0 && c_top <= grid.view.size.cy {
				for j in 0..row.cells.len(){
					let cell = (&row.cells[j]).clone();
					let grid_column = (&grid.columns[j]).clone();
					if grid_column.visible {
						if grid_column.frozen {
							let mut cell_width = grid_column.width;
							let col_span = cell.col_span;
							if col_span > 1 {
								for n in 1..col_span{
									let span_column = (&grid.columns[(grid_column.index + n) as usize]).clone();
									if span_column.visible {
										cell_width = cell_width + span_column.width;
									}
								}
							}
							let mut cell_height = grid.row_height;
							let row_span = cell.row_span;
							if row_span > 1 {
								for n in 1..row_span{
									let span_row = (&grid.rows[i + n as usize]).clone();
									if span_row.visible{
										cell_height = cell_height + grid.row_height;
									}
								}
							}
							let c_rect = FCRect{left:grid_column.bounds.left, top:r_top, right:grid_column.bounds.left + cell_width, bottom:r_top + cell_height};
							if c_rect.right >= 0.0 && c_rect.left < grid.view.size.cx {
							    draw_grid_cell(&context, grid, row.clone(), grid_column.clone(), cell.clone(), c_rect.left, c_rect.top, c_rect.right, c_rect.bottom);
							}
						}
					}
				}
			}
			if c_top > grid.view.size.cy{
				break;
            }
			c_top += grid.row_height;
		}
	}
}

/*
* Touch move method for grid
* grid: Grid
* first_touch:Is it first touch
* first_point:Point of first touch
* second_touch:Is it second touch
* second_point:Point of second touch
*/
pub fn touch_move_grid(grid:&mut FCGrid, first_touch:bool, first_point:FCPoint, second_touch:bool, second_point:FCPoint){
	if first_touch {
		let mp = first_point.clone();
		unsafe{
			if M_RESIZE_COLUMN_STATE != 0 {
				let mut grid_column = (&grid.columns[M_RESIZE_COLUMN_INDEX as usize]).clone();
				let new_width = M_RESIZE_COLUMN_BEGINWIDTH + (mp.x - grid.view.start_point.x);
				if new_width > 10.0 {
					grid_column.width = new_width;
				}
				grid.columns[M_RESIZE_COLUMN_INDEX as usize] = grid_column.clone();
				return;
			}
		}
		if grid.view.show_hscrollbar || grid.view.show_vscrollbar{
			if grid.view.down_scroll_hbutton {
				let content_width = get_grid_content_width(grid);
				let sub_x = (mp.x - grid.view.start_point.x) / grid.view.size.cx * content_width;
				let mut new_scrollh = grid.view.start_scroll_h + sub_x;
				if new_scrollh < 0.0 {
					new_scrollh = 0.0;
				} else if new_scrollh > content_width - grid.view.size.cx {
					new_scrollh = content_width - grid.view.size.cx;
				}
				grid.view.scroll_h = new_scrollh;
				unsafe{
					M_CANCEL_CLICK = true;
				}
				return;

			} else if grid.view.down_scroll_vbutton {
				let content_height = get_grid_content_height(grid);
				let sub_y = (mp.y - grid.view.start_point.y) / (grid.view.size.cy - grid.header_height - grid.view.scroll_size) * content_height;
				let mut new_scroll_v = grid.view.start_scroll_v + sub_y;
				if new_scroll_v < 0.0 {
					new_scroll_v = 0.0;
				} else if new_scroll_v > content_height - (grid.view.size.cy - grid.header_height - grid.view.scroll_size) {
					new_scroll_v = content_height - (grid.view.size.cy - grid.header_height - grid.view.scroll_size);
				}
				grid.view.scroll_v = new_scroll_v;
				unsafe{
					M_CANCEL_CLICK = true;
				}
				return;
			}
		}
		if grid.view.allow_drag_scroll {
			let content_width = get_grid_content_width(grid);
			if content_width > grid.view.size.cx - grid.view.scroll_size {
				let sub_x = grid.view.start_point.x - mp.x;
				let mut new_scrollh = grid.view.start_scroll_h + sub_x;
				if new_scrollh < 0.0 {
					new_scrollh = 0.0;
				} else if new_scrollh > content_width - grid.view.size.cx {
					new_scrollh = content_width - grid.view.size.cx;
				}
				grid.view.scroll_h = new_scrollh;
				if sub_x.abs() > 5.0{
				    unsafe{
						M_CANCEL_CLICK = true;
					}
				}
			}
			let content_height = get_grid_content_height(grid);
			if content_height > grid.view.size.cy - grid.header_height - grid.view.scroll_size {
				let sub_y = grid.view.start_point.y - mp.y;
				let mut new_scroll_v = grid.view.start_scroll_v + sub_y;
				if new_scroll_v < 0.0{
					new_scroll_v = 0.0;
				} else if new_scroll_v > content_height - (grid.view.size.cy - grid.header_height - grid.view.scroll_size) {
					new_scroll_v = content_height - (grid.view.size.cy - grid.header_height - grid.view.scroll_size);
				}
				grid.view.scroll_v = new_scroll_v;
				if sub_y.abs() > 5.0{
				    unsafe{
						M_CANCEL_CLICK = true;
					}
				}
			}
		}
	}
}

/*
* Touch down method for grid
* grid: Grid
* first_touch:Is it first touch
* first_point:Point of first touch
* second_touch:Is it second touch
* second_point:Point of second touch
*/
pub fn touch_down_grid(grid:&mut FCGrid, first_touch:bool, first_point:FCPoint, second_touch:bool, second_point:FCPoint){
	let mp = first_point.clone();
	grid.view.start_point = mp.clone();
	grid.view.down_scroll_hbutton = false;
	grid.view.down_scroll_vbutton = false;
	if grid.view.show_hscrollbar{
		let content_width = get_grid_content_width(grid);
		if content_width > 0.0 && content_width > grid.view.size.cx - grid.view.scroll_size {
		    let s_left = grid.view.scroll_h / content_width * grid.view.size.cx;
		    let mut s_right = (grid.view.scroll_h + grid.view.size.cx) / content_width * grid.view.size.cx;
		    if s_right - s_left < grid.view.scroll_size {
			    s_right = s_left + grid.view.scroll_size;
		    }
		    if mp.x >= s_left && mp.x <= s_right && mp.y >= grid.view.size.cy - grid.view.scroll_size && mp.y <= grid.view.size.cy {
			    grid.view.down_scroll_hbutton = true;
			    grid.view.start_scroll_h = grid.view.scroll_h;
			    return;
		    }
		}
	}
	if grid.view.show_vscrollbar{
	    let content_height = get_grid_content_height(grid);
		if content_height > 0.0 && content_height > grid.view.size.cy - grid.header_height - grid.view.scroll_size {
			let s_top = grid.header_height + grid.view.scroll_v / content_height * (grid.view.size.cy - grid.header_height - grid.view.scroll_size);
			let mut s_bottom  = grid.header_height + (grid.view.scroll_v + (grid.view.size.cy - grid.header_height - grid.view.scroll_size)) / content_height * (grid.view.size.cy - grid.header_height - grid.view.scroll_size);
			if s_bottom - s_top < grid.view.scroll_size {
				s_bottom = s_top + grid.view.scroll_size;
			}
			if mp.x >= grid.view.size.cx - grid.view.scroll_size && mp.x <= grid.view.size.cx && mp.y >= s_top && mp.y <= s_bottom {
				grid.view.down_scroll_vbutton = true;
				grid.view.start_scroll_v = grid.view.scroll_v;
				return;
			}
		}
	}
	if grid.view.allow_drag_scroll{
		grid.view.start_scroll_h = grid.view.scroll_h;
		grid.view.start_scroll_v = grid.view.scroll_v;
	}
	let mut col_left = 0.0;
	for i in 0..grid.columns.len(){
		let mut grid_column = (&grid.columns[i]).clone();
		let col_rect= FCRect{left:col_left, top:0.0, right:col_left + grid_column.width, bottom:grid.header_height};
		grid_column.bounds = col_rect;
		grid_column.index = i as i32;
		col_left = col_left + grid_column.width;
		grid.columns[i] = grid_column;
	}
	unsafe{
		M_RESIZE_COLUMN_STATE = 0;
		M_RESIZE_COLUMN_BEGINWIDTH = 0.0;
		if grid.header_height > 0.0 && mp.y <= grid.header_height {
			for i in 0..grid.columns.len(){
				let grid_column = (&grid.columns[i]).clone();
				if grid_column.visible {
					let bounds = grid_column.bounds;
					if mp.x >= bounds.left - grid.view.scroll_h && mp.x <= bounds.right - grid.view.scroll_h {
						if grid_column.index > 0 && mp.x < bounds.left + 5.0 - grid.view.scroll_h {
							M_RESIZE_COLUMN_STATE = 1;
							let last_column = (&grid.columns[(grid_column.index - 1) as usize]).clone();
							M_RESIZE_COLUMN_BEGINWIDTH = last_column.bounds.right - last_column.bounds.left;
							M_RESIZE_COLUMN_INDEX = grid_column.index - 1;
						}
						else if mp.x > bounds.right - 5.0 - grid.view.scroll_h {
							M_RESIZE_COLUMN_STATE = 2;
							M_RESIZE_COLUMN_BEGINWIDTH = bounds.right - bounds.left;
							M_RESIZE_COLUMN_INDEX = grid_column.index;
						}
						break;
					}
				}
			}
		}
	}
}

/*
* Touch up method for grid
* grid: Grid
* first_touch:Is it first touch
* first_point:Point of first touch
* second_touch:Is it second touch
* second_point:Point of second touch
*/
pub fn touch_up_grid(grid:&mut FCGrid, first_touch:bool, first_point:FCPoint, second_touch:bool, second_point:FCPoint){
	grid.view.down_scroll_hbutton = false;
	grid.view.down_scroll_vbutton = false;
	unsafe{
		if(M_RESIZE_COLUMN_STATE != 0){
			M_RESIZE_COLUMN_STATE = 0;
			return;
		}
		if M_CANCEL_CLICK{
			return;
		}
	}
	
	let mut c_left = 0.0;
	let mut c_top = -grid.view.scroll_v + grid.header_height;
	let mut col_left = 0.0;
	for i in 0..grid.columns.len(){
		let mut grid_column = (&grid.columns[i]).clone();
		let col_rect= FCRect{left:col_left, top:0.0, right:col_left + grid_column.width, bottom:grid.header_height};
		grid_column.bounds = col_rect;
		grid_column.index = i as i32;
		col_left = col_left + grid_column.width;
		grid.columns[i] = grid_column;
	}
	for i in 0..grid.rows.len(){
		let row = (&grid.rows[i]).clone();
		if row.visible {
			let r_top = c_top;
			let r_bottom = c_top + grid.row_height;
			if r_bottom >= 0.0 && c_top <= grid.view.size.cy {
				for j in 0..row.cells.len(){
					let cell = (&row.cells[j]).clone();
					let grid_column = (&grid.columns[j]).clone();
					if grid_column.visible {
						if grid_column.frozen {
							let mut cell_width = grid_column.width;
							let col_span = cell.col_span;
							if col_span > 1 {
								for n in 1..col_span{
									let span_column = (&grid.columns[(grid_column.index + n) as usize]).clone();
									if span_column.visible {
										cell_width = cell_width + span_column.width;
									}
								}
							}
							let mut cell_height = grid.row_height;
							let row_span = cell.row_span;
							if row_span > 1 {
								for n in 1..row_span{
									let span_row = (&grid.rows[i + n as usize]).clone();
									if span_row.visible {
										cell_height = cell_height + grid.row_height;
									}
								}
							}
							
							let c_rect = FCRect{left:grid_column.bounds.left, top:r_top, right:grid_column.bounds.left + cell_width, bottom:r_top + cell_height};
							if c_rect.right >= 0.0 && c_rect.left < grid.view.size.cx {
							    if first_point.x >= c_rect.left && first_point.x <= c_rect.right && first_point.y >= c_rect.top && first_point.y <= c_rect.bottom{
							        for r in 0..grid.rows.len(){
										let mut sub_row = (&grid.rows[r]).clone();
										if r == i{
											sub_row.selected = true
										}else{
											sub_row.selected = false
										}
										grid.rows[r] = sub_row
									}
									return;
							    }
							}
						}
					}
				}
			}
			if r_bottom >= 0.0 && c_top <= grid.view.size.cy {
				for j in 0..row.cells.len(){
					let cell = (&row.cells[j]).clone();
					let grid_column = (&grid.columns[j]).clone();
					if grid_column.visible {
						if !grid_column.frozen {
							let mut cell_width = grid_column.width;
							let col_span = cell.col_span;
							if col_span > 1 {
								for n in 1..col_span{
									let span_column = (&grid.columns[(grid_column.index + n) as usize]).clone();
									if span_column.visible {
										cell_width = cell_width + span_column.width;
									}
								}
							}
							let mut cell_height = grid.row_height;
							let row_span = cell.row_span;
							if row_span > 1 {
								for n in 1..row_span{
									let span_row = (&grid.rows[i + n as usize]).clone();
									if span_row.visible {
										cell_height = cell_height + grid.row_height;
									}
								}
							}
							
							let c_rect = FCRect{left:grid_column.bounds.left - grid.view.scroll_h, top:r_top, right:grid_column.bounds.left + cell_width - grid.view.scroll_h, bottom:r_top + cell_height};
							if c_rect.right >= 0.0 && c_rect.left < grid.view.size.cx {
							    if first_point.x >= c_rect.left && first_point.x <= c_rect.right && first_point.y >= c_rect.top && first_point.y <= c_rect.bottom{
							        for r in 0..grid.rows.len(){
										let mut sub_row = (&grid.rows[r]).clone();
										if r == i{
											sub_row.selected = true
										}else{
											sub_row.selected = false
										}
										grid.rows[r] = sub_row
									}
									return;
							    }
							}
						}
					}
				}
			}
			if c_top > grid.view.size.cy {
				break;
            }
			c_top = c_top + grid.row_height;
		}
	}
	if grid.header_height > 0.0 && first_point.y <= grid.header_height {
		for i in 0..grid.columns.len(){
			let grid_column = (&grid.columns[i]).clone();
			if grid_column.visible {
				if !grid_column.frozen {
					if first_point.x >= c_left && first_point.x <= c_left + grid_column.width{
				        return;
				    }
				}
				c_left = c_left + grid_column.width;
			}
		}
		c_left = -grid.view.scroll_h;
		for i in 0..grid.columns.len(){
			let grid_column = (&grid.columns[i]).clone();
			if grid_column.visible {
				if grid_column.frozen {
					if first_point.x >= c_left && first_point.x <= c_left + grid_column.width{
				        return;
				    }
				}
				c_left = c_left + grid_column.width;
			}
		}
	}
}

/*
* Mouse wheel method for grid
* grid:Grid
* delta:Delta
*/
pub fn touch_wheel_grid(grid:&mut FCGrid, delta:i32){
	let mut old_scroll_v = grid.view.scroll_v;
    if delta > 0 {
	    old_scroll_v = old_scroll_v - 20.0;
    } else if delta < 0 {
	    old_scroll_v = old_scroll_v + 20.0;
    }
    let content_height = get_grid_content_height(grid);
    if content_height < grid.view.size.cy - grid.header_height - grid.view.scroll_size {
        grid.view.scroll_v = 0.0;
    } else {
        if old_scroll_v < 0.0 {
	        old_scroll_v = 0.0;
	    } else if old_scroll_v > content_height - grid.view.size.cy + grid.header_height + grid.view.scroll_size {
		    old_scroll_v = content_height - grid.view.size.cy + grid.header_height + grid.view.scroll_size;
        }
        grid.view.scroll_v = old_scroll_v;
    }
}

/*
* Calculate coordinate axis
* min:Min value
* max:Max value
* y_len:Length
* max_span:Max span
* min_span:Min span
* defCount:Define count
* grid_step:Grid step
* grid_digit:Grid digit
*/
pub fn chart_grid_scale(min : f64, max : f64, y_len : f32, max_span : f32, min_span : f32, def_count : i32, grid_step:&mut f64, grid_digit:&mut i32){
	*grid_step = 0.0;
	*grid_digit = 0;
	let sub = max - min;
    let n_min_count = (y_len / max_span).ceil() as i32;
    let n_max_count = (y_len / min_span).floor() as i32 ;
    let mut n_count = def_count;
    let mut log_step = sub / (n_count as f64);
    let mut start : bool  = false;
    let mut divisor : f64 = 0.0;
    let mut i : i32 = 15;
	let mut n_temp : i32 = 0;
	n_count = n_min_count.max(n_count);
    n_count = n_max_count.min(n_count);
    n_count = n_count.max(1);
	while i>= -6{
		let b:f64 = 10.0;
		divisor = b.powf(i as f64);
		n_temp = (log_step / divisor).floor() as i32;
		if start {
            if n_temp < 4 {
                if *grid_digit > 0 {
                    *grid_digit = *grid_digit - 1;
                }
            } else if n_temp >= 4 && n_temp <= 6 {
                n_temp = 5;
                *grid_step = *grid_step + (n_temp as f64) * divisor;
            } else {
                *grid_step = *grid_step + 10.0 * divisor;
                if *grid_digit > 0 {
                    *grid_digit = *grid_digit - 1;
                }
            }
            break;
        } else if n_temp > 0 {
            *grid_step = (n_temp as f64) * divisor + *grid_step;
            log_step = log_step - *grid_step;
            start = true;
        }
        i = i - 1;
	}
}

/*
* Calculate parallelogram parameters
* x1:X1
* y1:Y1
* x2:X2
* y2:Y2
* x3:X3
* y3:Y3
*/
pub fn parallelogram(x1:f32, y1:f32, x2:f32, y2:f32, x3:f32, y3:f32, x4:&mut f32, y4:&mut f32){
	*x4 = x1 + x3 - x2;
    *y4 = y1 + y3 - y2;
}

/*
* Calculate average
* list:Collection
*/
pub fn avg_value(list:Vec<f64>)->f64{
	let len = list.len();
	let mut sum:f64 = 0.0;
	for num in list{
		sum = sum + num;
	}
	sum = sum / (len as f64);
	return sum;
}

/*
* Calculate max value
* list:Collection
*/
pub fn max_value(list:Vec<f64>)->f64{
	let mut max:f64 = 0.0;
	let len = list.len();
	if len > 0{
		max = list[0];
	}
	for num in list{
		if max < num{
			max = num;
		}
	}
	return max;
}

/*
* Calculate min value
* list:Collection
*/
pub fn min_value(list:Vec<f64>)->f64{
	let mut min:f64 = 0.0;
	let len = list.len();
	if len > 0{
		min = list[0];
	}
	for num in list{
		if min > num{
			min = num;
		}
	}
	return min;
}

/*
* Calculate the center of a circle based on three points
* x1:X1
* y1:Y1
* x2:X2
* y2:Y2
* x3:X3
* y3:Y3
* o_x: The x-coordinate of the center of the circle
* o_y: The y-coordinate of the center of the circle
* r: R
*/
pub fn ellipse_or(x1:f32, y1:f32, x2:f32, y2:f32, x3:f32, y3:f32, o_x:&mut f32, o_y:&mut f32, r:&mut f32){
	*o_x = ((y3 - y1) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1) + (y2 - y1) * (y1 * y1 - y3 * y3 + x1 * x1 - x3 * x3))
        / (2.0 * (x2 - x1) * (y3 - y1) - 2.0 * (x3 - x1) * (y2 - y1));
    *o_y = ((x3 - x1) * (x2 * x2 - x1 * x1 + y2 * y2 - y1 * y1) + (x2 - x1) * (x1 * x1 - x3 * x3 + y1 * y1 - y3 * y3))
        / (2.0 * (y2 - y1) * (x3 - x1) - 2.0 * (y3 - y1) * (x2 - x1));
    *r = ((x1 - *o_x) * (x1 - *o_x) + (y1 - *o_y) * (y1 - *o_y)).sqrt();
}

/*
* Calculate line parameters
* mp:Coordinate
* x1:X1
* y1:Y1
* x2:X2
* y2:Y2
* oX:OX
* oY:OY
* k:Line parameter k
* b:Line parameter b
*/
pub fn line_xy(x1:f32, y1:f32, x2:f32, y2:f32, o_x:f32, o_y:f32, k:&mut f32, b:&mut f32){
	if (x1 - o_x) != (x2 - o_x) {
        *k = ((y2 - o_y) - (y1 - o_y)) / ((x2 - o_x) - (x1 - o_x));
        *b = (y1 - o_y) - *k * (x1 - o_x);
    }
}

/*
* Determine if the point is on an ellipse
* x:X
* y:Y
* o_x:Coordinate start x
* o_y:Coordinate start y
* a:Ellipse parameter a
* b:Ellipse parameter b
*/
pub fn ellipse_has_point(x:f32, y: f32, o_x:f32, o_y:f32, a:f32, b:f32)->bool{
	let mut new_x = x;
	let mut new_y = y;
	new_x = x - o_x;
    new_y = y - o_y;
    if a == 0.0 && b == 0.0 && new_x == 0.0 && new_y == 0.0 {
        return true;
    }
    if a == 0.0 {
        if new_x == 0.0 && new_y >= -b && new_y <= b {
            return false;
        }
    }
    if b == 0.0 {
        if y == 0.0 && new_x >= -a && new_x <= a {
            return true;
        }
    }
    if (new_x * new_x) / (a * a) + (new_y * new_y) / (b * b) >= 0.8 && (new_x * new_x) / (a * a) + (new_y * new_y) / (b * b) <= 1.2 {
        return true;
    }
    return false;
}

/*
* Calculate rectangles based on coordinates
* x1:X1
* y1:Y1
* x2:X2
* y2:Y2
* x:X
* y:Y
* w:Width
* h:Height
*/
pub fn rectangle_xywh(x1:f32, y1:f32, x2:f32, y2:f32, x:&mut f32, y:&mut f32, w:&mut f32, h:&mut f32){
	if x1 < x2{
		*x = x1;
	}else{
		*x = x2;
	}
	if y1 < y2{
		*y = y1;
	}else{
		*y = y2;
	}
    *w = (x1 - x2).abs();
    *h = (y1 - y2).abs();
    if *w <= 0.0 {
        *w = 4.0;
    }
    if *h <= 0.0 {
        *h = 4.0;
    }
}

/*
* Determine whether to select a straight line
* mp:Coordinate
* x1:X1
* y1:Y1
* x2:X2
* y2:Y2
*/
pub fn select_line(mp:FCPoint, x1:f32, y1:f32, x2:f32, y2:f32)->bool{
	let mut k:f32 = 0.0;
	let mut b:f32 = 0.0;
	let f32_x = mp.x as f32;
	let f32_y = mp.y as f32;
	line_xy(x1, y1, x2, y2, 0.0, 0.0, &mut k, &mut b);
	if !(k == 0.0 && b == 0.0) {
        if f32_y / (f32_x * k + b) >= 0.9 && f32_y / (f32_x * k + b) <= 1.1 {
            return true;
        }
    } else {
        if f32_x >= x1 - 5.0 && f32_x <= x1 + 5.0 {
            return true;
        }
    }
    return false;
}

/*
* Determine whether to select a ray
* mp:Coordinate
* x1:X1
* y1:Y1
* x2:X2
* y2:Y2
*/
pub fn select_ray(mp:FCPoint, x1:f32, y1:f32, x2:f32, y2:f32)->bool{
	let mut k:f32 = 0.0;
	let mut b:f32 = 0.0;
	let f32_x = mp.x as f32;
	let f32_y = mp.y as f32;
	line_xy(x1, y1, x2, y2, 0.0, 0.0, &mut k, &mut b);
	if !(k == 0.0 && b == 0.0) {
        if f32_y / (f32_x * k + b) >= 0.9 && f32_y / (f32_x * k + b) <= 1.1 {
            if x1 >= x2{
                if f32_x > x1 + 5.0 {
					return false;
				}
            } else if x1 < x2 {
                if f32_x < x1 - 5.0{
					return false;
				}
            }
            return true;
        }
    } else {
        if f32_x>= x1 - 5.0 && f32_x <= x1 + 5.0{
            if y1 >= y2 {
                if f32_y <= y1 - 5.0 {
                    return true;
                }
            } else {
                if f32_y >= y1 - 5.0 {
                    return true;
                }
            }
        }
    }
    return false;
}

/*
* Determine whether to select a line segment
* mp:Coordinate
* x1:X1
* y1:Y1
* x2:X2
* y2:Y2
*/
pub fn select_segment(mp:FCPoint, x1:f32, y1:f32, x2:f32, y2:f32)->bool{
	let mut k:f32 = 0.0;
	let mut b:f32 = 0.0;
	let f32_x = mp.x as f32;
	let f32_y = mp.y as f32;
	line_xy(x1, y1, x2, y2, 0.0, 0.0, &mut k, &mut b);
	let mut small_x:f32 = 0.0;
	let mut small_y:f32 = 0.0;
	let mut big_x:f32 = 0.0;
	let mut big_y:f32 = 0.0;
	if x1 <= x2{
		small_x = x1;
	}else{
		small_x = x2;
	}
	if y1 <= y2{
		small_y = y1;
	}else{
		small_y = y2;
	}
	if x1 > x2{
		big_x = x1;
	}else{
		big_x = x2;
	}
	if y1 > y2{
		big_y = y1;
	}else{
		big_y = y2;
	}
    if f32_x >= small_x - 2.0 && f32_x <= big_x + 2.0 && f32_y >= small_y - 2.0 && f32_y <= big_y + 2.0 {
        if k != 0.0 || b != 0.0 {
            if f32_y / (f32_x * k + b) >= 0.9 && f32_y / (f32_x * k + b) <= 1.1 {
                return true;
            }
        } else {
            if f32_x >= x1 - 5.0 && f32_x <= x1 + 5.0{
                return true;
            }
        }
    }
    return false;
}

/*
* Calculate linear regression
* list:Collection
* rk:Line parameter k
* rb:Line parameter b
*/
pub fn linear_regression_equation(list:Vec<f64>, rk:&mut f32, rb:&mut f32){
	let mut sux:f64 = 0.0;
    let mut suy:f64 = 0.0;
    let mut suup:f64 = 0.0;
    let mut sudown:f64 = 0.0;
    let mut x_avg:f64 = 0.0;
    let mut y_avg:f64 = 0.0;
    let length = list.len();
    if length > 1{
		for i in 0..length{
			sux = sux + (i as f64) + 1.0;
            suy = suy + list[i];
		}
        x_avg = sux / (length as f64);
        y_avg = suy / (length as f64);
		for i in 0..length{
			suup = suup + ((i as f64) + 1.0 - x_avg) * (list[i] - y_avg);
            sudown = sudown + ((i as f64) + 1.0 - x_avg) * ((i as f64)+ 1.0 - x_avg);
		}
        *rk = (suup / sudown) as f32;
        *rb = (y_avg - (*rk as f64) * x_avg) as f32;
    }
}

/*
* Calculate sum of standard deviation
* list:Collection
* avg_value:Average value
* param:Paramter
*/
pub fn standard_deviation_sum(list:Vec<f64>, avg_value:f64, param:f64)->f64{
	let target_value:f64 = list[list.len() - 1];
	let mut sum = (target_value - avg_value) * (target_value - avg_value);
	for i in 0..(list.len() - 1){
		let ileft = list[i];
        sum = sum + (ileft - avg_value) * (ileft - avg_value);
	}
	return sum;
}

/*
* Calculate fibonacci sequence
* index:Index
*/
pub fn fibonacci_value(index:i32)->i32{
	if index < 1{
        return 0;
    }
    else{
        let mut vlist: Vec<i32> = Vec::new();
		for i in 0..index{
			vlist.push(0);
		}
        let mut result:i32 = 0;
		for i in 0..index{
			if i == 0 || i == 1{
				vlist[i as usize] = 1;
			}else{
				vlist[i as usize] = vlist[(i - 1)  as usize] + vlist[(i - 2) as usize];
			}
		}
        result = vlist[(index - 1) as usize];
        return result;
    }
}

/*
* Obtain the maximum number of displayed records
* chart:Chart
* h_scale_pixel:Interval
* pure_h:Lateral distance
*/
pub fn get_max_visible_count(chart:&mut FCChart, h_scale_pixel:f32, pure_h:f32)->i32{
	let mut count = ((pure_h - h_scale_pixel) / h_scale_pixel) as i32;
    if count < 0{
        count = 0;
    }
    return count;
}

/*
* Obtain the height of the K-line layer
* chart:Chart
*/
pub fn get_candle_div_height(chart:&mut FCChart)->f32{
	let height = chart.view.size.cy - chart.hscale_height;
	if height > 0.0{
		return height * (chart.candle_div_percent as f32);
	}else{
		return 0.0;
	}
}

/*
* Obtain the height of the transaction volume layer
* chart:Chart
*/
pub fn get_vol_div_height(chart:&mut FCChart)->f32{
	let height = chart.view.size.cy - chart.hscale_height;
	if height > 0.0{
		return height * (chart.vol_div_percent as f32);
	}else{
		return 0.0;
	}
}

/*
* Obtain the height of the indicator layer
* chart:Chart
*/
pub fn get_ind_div_height(chart:&mut FCChart)->f32{
	let height = chart.view.size.cy - chart.hscale_height;
	if height > 0.0{
		return height * (chart.ind_div_percent as f32);
	}else{
		return 0.0;
	}
}

/*
* Obtain the height of the indicator2 layer
* chart:Chart
*/
pub fn get_ind_div_height2(chart:&mut FCChart)->f32{
	let height = chart.view.size.cy - chart.hscale_height;
	if height > 0.0{
		return height * (chart.ind_div_percent2 as f32);
	}else{
		return 0.0;
	}
}

/*
* Get horizontal workspace
* chart:Chart
*/
pub fn get_chart_workarea_width(chart:&mut FCChart)->f32{
	return chart.view.size.cx - chart.left_vscale_width - chart.right_vscale_width - chart.right_space;
}

/*
* Obtain abscissa based on index
* chart:Chart
* index:Index
*/
pub fn get_chart_x(chart:&mut FCChart, index:i32)->f32{
	return chart.left_vscale_width + ((index - chart.first_visible_index) as f32) * chart.hscale_pixel + chart.hscale_pixel;
}

/*
* Calculate index based on location
* chart:Chart
* mp:Coordinate
*/
pub fn get_chart_index(chart:&mut FCChart, mp:FCPoint)->i32{
	let data_len = chart.data.len() as i32;
	if data_len == 0{
		return -1;
	}
	if mp.x <= 0.0 {
		return 0;
	}
	let width = chart.view.size.cx - chart.left_vscale_width - chart.right_vscale_width;
	let int_x = mp.x - chart.left_vscale_width - chart.hscale_pixel;
	let mut index = (chart.first_visible_index as f32 + int_x / chart.hscale_pixel) as i32;
	if chart.hscale_pixel >= 1.0{
		if (int_x as i32) % (chart.hscale_pixel as i32) != 0{
			index = index + 1;
		}
	}
	if index < 0{
		 index = 0;
	}else if index > data_len - 1{
		 index = data_len - 1;
	}	
	return index;
}

/*
* Retrieve index based on date
* chart:Chart
* date:Date
*/
pub fn get_chart_index_by_date(chart:&mut FCChart,date:f64)->i32{
	let data_len = chart.data.len() as i32;
	let mut index : i32 = -1;
	let mut pos : i32 = 0;
	let vecter_iterator = chart.data.iter();
	for data in vecter_iterator{
		if data.date == date{
			index = pos;
			break;
		}
		pos = pos + 1;
	}
	return index;
}

/*
* Retrieve date based on index
* chart:Chart
* index:Index
*/
pub fn get_chart_date_by_index(chart:&mut FCChart, index:i32)->f64{
	let mut date : f64 = 0.0;
	let data_len = chart.data.len() as i32;
    if index >= 0 && index < data_len{
        date = chart.data[index as usize].date;
    }
    return date;
}

/*
* Check last visible index
* chart:Chart
*/
pub fn check_chart_last_visible_index(chart:&mut FCChart){
	let data_len = chart.data.len() as i32;
    if chart.last_visible_index > data_len - 1 {
        chart.last_visible_index = data_len - 1;
    }
    if data_len > 0 && chart.last_visible_index != -1 {
        chart.last_visible_key = chart.data[chart.last_visible_index as usize].date;
        if chart.last_visible_index == data_len - 1 {
            chart.last_record_is_visible = true;
        } else {
            chart.last_record_is_visible = false;
        }
    } else {
        chart.last_visible_key = 0.0;
        chart.last_record_is_visible = true;
    }
}

/*
* Set visible index of chart
* chart:Chart
* first_visible_index:Start index
* last_visible_index:End index
*/
pub fn set_chart_visible_index(chart:&mut FCChart, first_visible_index : i32, last_visible_index : i32){
    let xscale_pixel = get_chart_workarea_width(chart) / ((last_visible_index - first_visible_index + 1) as f32);
    if xscale_pixel < 1000000.0 {
        chart.first_visible_index = first_visible_index;
        chart.last_visible_index = last_visible_index;
	    let data_len = chart.data.len() as i32;
        if last_visible_index != data_len - 1{
                chart.last_record_is_visible = false;
        }else {
            chart.last_record_is_visible = true;
        }
        chart.hscale_pixel = xscale_pixel;
        check_chart_last_visible_index(chart);
    }
}

/*
* Automatically set the first visible and last visible record numbers
* chart:Chart
*/
pub fn reset_chart_visible_record(chart:&mut FCChart){
    let rows_count = chart.data.len() as i32;
    let working_area_width = get_chart_workarea_width(chart);
    if chart.auto_fill_hscale {
        if working_area_width > 0.0 && rows_count > 0 {
            chart.hscale_pixel = working_area_width / (rows_count as f32);
            chart.first_visible_index = 0;
            chart.last_visible_index = rows_count - 1;
        }
    } else {
        let max_visible_record = get_max_visible_count(chart, chart.hscale_pixel, working_area_width);
        if rows_count == 0 {
            chart.first_visible_index = -1;
            chart.last_visible_index = -1;
        } else {
            if rows_count < max_visible_record {
                chart.last_visible_index = rows_count - 1;
                chart.first_visible_index = 0;
            }
            else {
                if chart.first_visible_index != -1 && chart.last_visible_index != -1 && !chart.last_record_is_visible{
                    let index = get_chart_index_by_date(chart, chart.last_visible_key);
                    if index != -1 {
                        chart.last_visible_index = index;
                    }
                    chart.first_visible_index = chart.last_visible_index - max_visible_record + 1;
                    if chart.first_visible_index < 0 {
                        chart.first_visible_index = 0;
                        chart.last_visible_index = chart.first_visible_index + max_visible_record;
                        check_chart_last_visible_index(chart);
                    }
                } else {
                    chart.last_visible_index = rows_count - 1;
                    chart.first_visible_index = chart.last_visible_index - max_visible_record + 1;
                    if chart.first_visible_index > chart.last_visible_index {
                        chart.first_visible_index = chart.last_visible_index;
                    }
                }
            }
        }
    }
}

/*
* Obtain the area of the K line
* chart: Chart
* plot: Plot
* n_high:High value
* n_low:Low value
*/
pub fn get_candle_range(chart:&mut FCChart, plot:&mut FCPlot, n_high:&mut f64, n_low:&mut f64){
    let mut bindex = get_chart_index_by_date(chart, plot.key1);
    let mut eindex = get_chart_index_by_date(chart, plot.key2);
    let mut temp_bindex : i32 = 0;
	let mut temp_eindex : i32 = 0;
	if bindex > eindex{
		temp_bindex = eindex;
		temp_eindex = bindex;
	}else{
		temp_bindex = bindex;
		temp_eindex = eindex;
	}
    bindex = temp_bindex;
    eindex = temp_eindex;
	let mut high_list: Vec<f64> = Vec::new();
	let mut low_list: Vec<f64> = Vec::new();
	for i in bindex..(eindex + 1){
		high_list.push(chart.data[i as usize].high);
        low_list.push(chart.data[i as usize].low);
	}
    *n_high = max_value(high_list);
    *n_low = min_value(low_list);
}

/*
* Calculate the position of numerical values in the layer
* chart:Chart
* div_index:Index of div
* value:Value
*/
pub fn get_chart_y(chart:&mut FCChart, div_index:i32, value:f64)->f32{
    if div_index == 0{
        if chart.candle_max > chart.candle_min{
            let mut c_value = value;
            let mut c_max = chart.candle_max;
            let mut c_min = chart.candle_min;
            if chart.vscale_type != "standard"{
                if c_value > 0.0 {
                    c_value = c_value.log10();
                } else if c_value < 0.0 {
                    c_value = -c_value.abs().log10();
                }
                if c_max > 0.0 {
                    c_max = c_max.log10();
                } else if c_max < 0.0 {
                    c_max = -c_max.abs().log10();
                }
                if c_min > 0.0 {
                    c_min = c_min.log10();
                } else if c_min < 0.0 {
                    c_min = -c_min.abs().log10();
                }
            }
            let rate = (c_value - c_min) / (c_max - c_min);
            let div_height = get_candle_div_height(chart);
            return div_height - chart.candle_padding_bottom - (div_height - chart.candle_padding_top - chart.candle_padding_bottom) * (rate as f32);
        }else{
            return 0.0;
        }
    }else if div_index == 1{
        if chart.vol_max > chart.vol_min{
            let rate = (value - chart.vol_min) / (chart.vol_max - chart.vol_min);
            let candle_height = get_candle_div_height(chart);
            let vol_height = get_vol_div_height(chart);
            return candle_height + vol_height - chart.vol_padding_bottom - (vol_height - chart.vol_padding_top - chart.vol_padding_bottom) * (rate as f32);
        }else{
            return 0.0;
        }
    }else if div_index == 2{
        if chart.ind_max > chart.ind_min{
            let rate = (value - chart.ind_min) / (chart.ind_max - chart.ind_min);
            let candle_height = get_candle_div_height(chart);
            let vol_height = get_vol_div_height(chart);
            let ind_height = get_ind_div_height(chart);
            return candle_height + vol_height + ind_height - chart.ind_padding_bottom - (ind_height - chart.ind_padding_top - chart.ind_padding_bottom) * (rate as f32);
        }else{
            return 0.0;
        }
    }
    else if div_index == 3{
        if chart.ind_max2 > chart.ind_min2{
            let rate = (value - chart.ind_min2) / (chart.ind_max2 - chart.ind_min2);
            let candle_height = get_candle_div_height(chart);
            let vol_height = get_vol_div_height(chart);
            let ind_height = get_ind_div_height(chart);
            let ind_height2 = get_ind_div_height2(chart);
            return candle_height + vol_height + ind_height + ind_height2 - chart.ind_padding_bottom2 - (ind_height2 - chart.ind_padding_top2 - chart.ind_padding_bottom2) * (rate as f32);
        }else{
            return 0.0;
        }
    }
    return 0.0;
}

/*
* Obtain corresponding values based on coordinates
* chart:Chart
* point:Coordinate
*/
pub fn get_chart_value(chart:&mut FCChart, point:FCPoint)->f64{
    let candle_height = get_candle_div_height(chart);
    let vol_height = get_vol_div_height(chart);
    let ind_height = get_ind_div_height(chart);
    let ind_height2 = get_ind_div_height2(chart);
    if point.y <= candle_height{
        let rate = (candle_height - chart.candle_padding_bottom - point.y) / (candle_height - chart.candle_padding_top - chart.candle_padding_bottom);
        let mut c_min = chart.candle_min;
        let mut c_max = chart.candle_max;
        if chart.vscale_type != "standard"{
            if c_max > 0.0 {
                c_max = c_max.log10();
            } else if c_max < 0.0 {
                c_max = -c_max.abs().log10();
            }
            if c_min > 0.0 {
                c_min = c_min.log10();
            } else if c_min < 0.0 {
                c_min = -c_min.abs().log10();
            }
        }
        let result = c_min + (c_max - c_min) * (rate as f64);;
        if chart.vscale_type != "standard"{
            let b:f64 = 10.0;
            return b.powf(result as f64);
        }else{
            return result;
        }
    }
    else if point.y > candle_height && point.y <= candle_height + vol_height{
        let rate = (vol_height - chart.vol_padding_bottom - (point.y - candle_height)) / (vol_height - chart.vol_padding_top - chart.vol_padding_bottom);
        return chart.vol_min + (chart.vol_max - chart.vol_min) * (rate as f64);
    }else if point.y > candle_height + vol_height && point.y <= candle_height + vol_height + ind_height{
        let rate = (ind_height - chart.ind_padding_bottom - (point.y - candle_height - vol_height)) / (ind_height - chart.ind_padding_top - chart.ind_padding_bottom);
        return chart.ind_min + (chart.ind_max - chart.ind_min) * (rate as f64);
    }else if point.y > candle_height + vol_height + ind_height && point.y <= candle_height + vol_height + ind_height + ind_height2{
        let rate = (ind_height2 - chart.ind_padding_bottom2 - (point.y - candle_height - vol_height - ind_height)) / (ind_height2 - chart.ind_padding_top2 - chart.ind_padding_bottom2);
        return chart.ind_min2 + (chart.ind_max2 - chart.ind_min2) * (rate as f64);
    }
    return 0.0;
}

/*
* Obtain corresponding values based on coordinates
* chart:Chart
* point:Coordinate
*/
pub fn get_candle_div_value(chart:&mut FCChart, point:FCPoint)->f64{
    let candle_height = get_candle_div_height(chart);
    let rate = (candle_height - chart.candle_padding_bottom - point.y) / (candle_height - chart.candle_padding_top - chart.candle_padding_bottom);
    let mut c_min = chart.candle_min;
    let mut c_max = chart.candle_max;
    if chart.vscale_type != "standard"{
        if c_max > 0.0{
            c_max = c_max.log10();
        } else if c_max < 0.0 {
            c_max = -c_max.abs().log10();
        }
        if c_min > 0.0 {
            c_min = c_min.log10();
        } else if c_min < 0.0 {
            c_min = -c_min.abs().log10();
        }
    }
    let result = c_min + (c_max - c_min) * (rate as f64);;
    if chart.vscale_type != "standard"{
        let b:f64 = 10.0;
        return b.powf(result as f64);
    }else{
        return result;
    }
}

/*
* Determine whether to select a line
* chart:Chart
* mp:Coordinate
* div_index:Index of div
* datas:Data list
* cur_index:Current index
*/
pub fn select_lines(chart:&mut FCChart, mp:FCPoint, div_index:i32, datas:Vec<f64>, cur_index:i32)->bool{
    if datas.len() > 0{
	    let top_y = get_chart_y(chart, div_index, datas[cur_index as usize]);
        if chart.hscale_pixel <= 1.0 {
            if mp.y >= top_y - 8.0 && mp.y <= top_y + 8.0 {
                return true;
            }
        } else {
            let index = cur_index;
            let scale_x = get_chart_x(chart, index);
            let mut judge_top = 0.0;
            let mut judge_scale_x = scale_x;
            if mp.x >= scale_x {
                let left_index = cur_index + 1;
                if cur_index < chart.last_visible_index {
                    let right_value = datas[left_index as usize];
                    judge_top = get_chart_y(chart, div_index, right_value);
                }
                else {
                    judge_top = top_y;
                }
            }
            else {
                judge_scale_x = scale_x - chart.hscale_pixel;
                let right_index = cur_index - 1;
                if cur_index > 0 {
                    let left_value = datas[right_index as usize];
                    judge_top = get_chart_y(chart, div_index, left_value);
                }else {
                    judge_top = top_y;
                }
            }
            let line_width : f32 = 4.0;
            let mut judge_x : f32 = 0.0;
            let mut judge_y : f32 = 0.0;
            let mut judge_w : f32 = 0.0;
            let mut judge_h : f32 = 0.0;
            if judge_top >= top_y {
                judge_x = judge_scale_x;
                judge_y = top_y - 2.0 - line_width;
                judge_w = chart.hscale_pixel;
                if judge_top - top_y + line_width < 4.0{
				    judge_h = 4.0;
                }else{
				    judge_h = judge_top - top_y + 4.0 + line_width;
                }
            }
            else {
                judge_x = judge_scale_x;
                judge_y = judge_top - 2.0 - line_width / 2.0;
                judge_w = chart.hscale_pixel;
                if top_y - judge_top + line_width < 4.0{
				    judge_h = 4.0;
                }else{
				    judge_h = top_y - judge_top + 4.0 + line_width;
                }
            }
       
            if mp.x >= judge_x && mp.x <= judge_x + judge_w && mp.y >= judge_y && mp.y <= judge_y + judge_h {
           
                return true;
            }
        }
    }
    return false;
}

/*
* Determine whether to select a graphic
* chart:Chart
* mp:Coordinate
*/
pub fn select_shape(chart:&mut FCChart, mp:FCPoint){
	chart.select_shape = "".to_string();
    chart.select_shape_ex = "".to_string();
	let data_len = chart.data.len() as i32;
	if data_len == 0{
		return;
	}
    let candle_height = get_candle_div_height(chart);
    let vol_height = get_vol_div_height(chart);
    let ind_height = get_ind_div_height(chart);
    let index = get_chart_index(chart, mp.clone());
    if mp.y >= candle_height + vol_height && mp.y <= candle_height + vol_height + ind_height {
        if chart.show_indicator == "MACD" {
            let macd_y = get_chart_y(chart, 2, chart.allmacdarr[index as usize]);
            let zero_y = get_chart_y(chart, 2, 0.0);
            if select_lines(chart, mp.clone(), 2, chart.allmacdarr.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "MACD".to_string();
            }
            if select_lines(chart, mp.clone(), 2, chart.alldifarr.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "DIF".to_string();
            }
            else if select_lines(chart, mp.clone(), 2, chart.alldeaarr.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "DEA".to_string();
            }
        } else if chart.show_indicator == "KDJ" {
            if select_lines(chart, mp.clone(), 2, chart.kdj_k.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "K".to_string();
            }
            else if select_lines(chart, mp.clone(), 2, chart.kdj_d.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "D".to_string();
            } else if select_lines(chart, mp.clone(), 2, chart.kdj_j.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "J".to_string();
            }
        } else if chart.show_indicator == "RSI" {
            if select_lines(chart, mp.clone(), 2, chart.rsi1.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "6".to_string();
            }
            else if select_lines(chart, mp.clone(), 2, chart.rsi2.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "12".to_string();
            } else if select_lines(chart, mp.clone(), 2, chart.rsi3.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "24".to_string();
            }
        }
        else if chart.show_indicator == "BIAS" {
            if select_lines(chart, mp.clone(), 2, chart.bias1.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "1".to_string();
            }
            else if select_lines(chart, mp.clone(), 2, chart.bias2.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "2".to_string();
            } else if select_lines(chart, mp.clone(), 2, chart.bias3.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "3".to_string();
            }
        }
        else if chart.show_indicator == "ROC" {
            if select_lines(chart, mp.clone(), 2, chart.roc.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "ROC".to_string();
            }
            else if select_lines(chart, mp.clone(), 2, chart.roc_ma.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "ROCMA".to_string();
            }
        } else if chart.show_indicator == "WR" {
            if select_lines(chart, mp.clone(), 2, chart.wr1.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "1".to_string();
            }
            else if select_lines(chart, mp.clone(), 2, chart.wr2.clone(), index) {
                chart.select_shape = "WR".to_string();
                chart.select_shape_ex = "2".to_string();
            }
        } else if chart.show_indicator == "CCI" {
            if select_lines(chart, mp.clone(), 2, chart.cci.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
            }
        } else if chart.show_indicator == "BBI" {
            if select_lines(chart, mp.clone(), 2, chart.bbi.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
            }
        } else if chart.show_indicator == "TRIX" {
            if select_lines(chart, mp.clone(), 2, chart.trix.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "TRIX".to_string();
            }
            else if select_lines(chart, mp.clone(), 2, chart.trix_ma.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "TRIXMA".to_string();
            }
        } else if chart.show_indicator == "DMA" {
            if select_lines(chart, mp.clone(), 2, chart.dma1.clone(), index) {
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "DIF".to_string();
            }
            else if select_lines(chart, mp.clone(), 2, chart.dma2.clone(), index){
                chart.select_shape = chart.show_indicator.clone();
                chart.select_shape_ex = "DIFMA".to_string();
            }
        }
    }
    else if mp.y >= candle_height && mp.y <= candle_height + vol_height {
        let vol_y = get_chart_y(chart, 1, chart.data[index as usize].volume);
        let zero_y = get_chart_y(chart, 1, 0.0); 
        if mp.y >= vol_y.min(zero_y) && mp.y <= vol_y.max(zero_y) {
            chart.select_shape = "VOL".to_string();
        }
    }
    else if mp.y >= 0.0 && mp.y <= candle_height {
        let is_trend:bool = false;
        if !is_trend {
            if chart.main_indicator == "BOLL" {
                if select_lines(chart, mp.clone(), 0, chart.boll_mid.clone(), index) {
                    chart.select_shape = chart.main_indicator.clone();
                    chart.select_shape_ex = "MID".to_string();
                }
                else if select_lines(chart, mp.clone(), 0, chart.boll_up.clone(), index) {
                    chart.select_shape = chart.main_indicator.clone();
                    chart.select_shape_ex = "UP".to_string();
                } else if select_lines(chart, mp.clone(), 0, chart.boll_down.clone(), index) {
                    chart.select_shape = chart.main_indicator.clone();
                    chart.select_shape_ex = "DOWN".to_string();
                }
            } else if chart.main_indicator == "MA" {
                if select_lines(chart, mp.clone(), 0, chart.ma5.clone(), index) {
                    chart.select_shape = chart.main_indicator.clone();
                    chart.select_shape_ex = "5".to_string();
                }
                else if select_lines(chart, mp.clone(), 0, chart.ma10.clone(), index) {
                    chart.select_shape = chart.main_indicator.clone();
                    chart.select_shape_ex = "10".to_string();
                }
                else if select_lines(chart, mp.clone(), 0, chart.ma20.clone(), index) {
                    chart.select_shape = chart.main_indicator.clone();
                    chart.select_shape_ex = "20".to_string();
                }
                else if select_lines(chart, mp.clone(), 0, chart.ma30.clone(), index) {
                    chart.select_shape = chart.main_indicator.clone();
                    chart.select_shape_ex = "30".to_string();
                }
                else if select_lines(chart, mp.clone(), 0, chart.ma120.clone(), index) {
                    chart.select_shape = chart.main_indicator.clone();
                    chart.select_shape_ex = "120".to_string();
                }
                else if select_lines(chart, mp.clone(), 0, chart.ma250.clone(), index) {
                    chart.select_shape = chart.main_indicator.clone();
                    chart.select_shape_ex = "250".to_string();
                }
            }
        }
        if chart.select_shape == "" {
            let high_y = get_chart_y(chart, 0, chart.data[index as usize].high);
            let low_y = get_chart_y(chart, 0, chart.data[index as usize].low);
			if mp.y >= low_y.min(high_y) && mp.y <= low_y.max(high_y) {
                chart.select_shape = "CANDLE".to_string();
            }
        }
    }
}

/*
* Clear cached data
* chart:Chart
*/
pub fn clear_data_arr(chart:&mut FCChart){
	let allema12 = Vec::new();
	let allema26 = Vec::new();
	let alldifarr = Vec::new();
	let alldeaarr = Vec::new();
	let allmacdarr = Vec::new();
	let boll_up = Vec::new();
	let boll_down = Vec::new();
	let boll_mid = Vec::new();
	let bias1 = Vec::new();
	let bias2 = Vec::new();
	let bias3 = Vec::new();
	let kdj_k = Vec::new();
	let kdj_d = Vec::new();
	let kdj_j = Vec::new();
	let rsi1 = Vec::new();
	let rsi2 = Vec::new();
	let rsi3 = Vec::new();
	let roc = Vec::new();
	let roc_ma = Vec::new();
	let wr1 = Vec::new();
	let wr2 = Vec::new();
	let cci = Vec::new();
	let bbi = Vec::new();
	let trix = Vec::new();
	let trix_ma = Vec::new();
	let dma1 = Vec::new();
	let dma2 = Vec::new();
	let ma5 = Vec::new();
	let ma10 = Vec::new();
	let ma20 = Vec::new();
	let ma30 = Vec::new();
	let ma120 = Vec::new();
	let ma250 = Vec::new();
	chart.allema12 = allema12;
	chart.allema26 = allema26;
	chart.alldifarr = alldifarr;
	chart.alldeaarr = alldeaarr;
	chart.allmacdarr = allmacdarr;
	chart.boll_up = boll_up;
	chart.boll_down = boll_down;
	chart.boll_mid = boll_mid;
	chart.bias1 = bias1;
	chart.bias2 = bias2;
	chart.bias3 = bias3;
	chart.kdj_k = kdj_k;
	chart.kdj_d = kdj_d;
	chart.kdj_j = kdj_j;
	chart.rsi1 = rsi1;
	chart.rsi2 = rsi2;
	chart.rsi3 = rsi3;
	chart.roc = roc;
	chart.roc_ma = roc_ma;
	chart.wr1 = wr1;
	chart.wr2 = wr2;
	chart.cci = cci;
	chart.bbi = bbi;
	chart.trix = trix;
	chart.trix_ma = trix_ma;
	chart.dma1 = dma1;
	chart.dma2 = dma2;
	chart.ma5 = ma5;
	chart.ma10 = ma10;
	chart.ma20 = ma20;
	chart.ma30 = ma30;
	chart.ma120 = ma120;
	chart.ma250 = ma250;
}

/*
* Calculate indicator
* chart:Chart
*/
pub fn calc_chart_indicator(chart:&mut FCChart){
	clear_data_arr(chart);
	let mut close_arr = Vec::new();
	let mut high_arr = Vec::new();
	let mut low_arr = Vec::new();
	let data_len = chart.data.len() as i32;
	for i in 0..data_len{
        let close = chart.data[i as usize].close;
        let high = chart.data[i as usize].high;
        let low = chart.data[i as usize].low;
        close_arr.push(close);
        high_arr.push(high);
        low_arr.push(low);
    }
    if chart.main_indicator == "BOLL" {
		get_boll_data(close_arr.clone(), 20, &mut chart.boll_up, &mut chart.boll_mid, &mut chart.boll_down);
    } else if chart.main_indicator == "MA" {
		chart.ma5 = ma_value(close_arr.clone(), 5);
		chart.ma10 = ma_value(close_arr.clone(), 10);
		chart.ma20 = ma_value(close_arr.clone(), 20);
		chart.ma30 = ma_value(close_arr.clone(), 30);
		chart.ma120 = ma_value(close_arr.clone(), 120);
		chart.ma250 = ma_value(close_arr.clone(), 250);
    }
    if chart.show_indicator == "BIAS" {
		get_bias_data(close_arr.clone(), 6, 12, 24, &mut chart.bias1, &mut chart.bias2, &mut chart.bias3);
	}
	else if chart.show_indicator == "DMA"{
		get_dma_data(close_arr.clone(), 10, 50, &mut chart.dma1, &mut chart.dma2);
	}
	else if chart.show_indicator == "BBI"{
		get_bbi_data(close_arr.clone(), 3, 6, 12, 24, &mut chart.bbi);
	}
	else if chart.show_indicator == "RSI"{
		get_rsi_data(close_arr.clone(), 6, 12, 24, &mut chart.rsi1, &mut chart.rsi2, &mut chart.rsi3);
	}
	else if chart.show_indicator == "ROC"{
		get_roc_data(close_arr.clone(), 12, 6, &mut chart.roc, &mut chart.roc_ma);
	}
	else if chart.show_indicator == "TRIX"{
		get_trix_data(close_arr.clone(), 10, 50, &mut chart.trix, &mut chart.trix_ma);
	}
	else if chart.show_indicator == "KDJ"{
		get_kdj_data(high_arr.clone(), low_arr.clone(), close_arr.clone(), 9, 3, 3, &mut chart.kdj_k, &mut chart.kdj_d, &mut chart.kdj_j);
	}
	else if chart.show_indicator == "WR"{
		get_wr_data(high_arr.clone(), low_arr.clone(), close_arr.clone(), 5, 10, &mut chart.wr1, &mut chart.wr2);
	}
	else if chart.show_indicator == "CCI"{
		get_cci_data(high_arr.clone(), low_arr.clone(), close_arr.clone(), 14, &mut chart.cci);
	}
	else if chart.show_indicator == "MACD"{
		chart.allema12.push(close_arr[0]);
        chart.allema26.push(close_arr[0]);
	    chart.alldeaarr.push(0.0);
	    for i in 1..close_arr.len(){
			chart.allema12.push(get_ema(12, close_arr[i], chart.allema12[i - 1]));
            chart.allema26.push(get_ema(26, close_arr[i], chart.allema26[i - 1]));
	    }
        chart.alldifarr = get_dif(chart.allema12.clone(), chart.allema26.clone());
        for i in 1..chart.alldifarr.len(){  
            chart.alldeaarr.push(chart.alldeaarr[i - 1] * 8.0 / 10.0 + chart.alldifarr[i] * 2.0 / 10.0);
	    }
        chart.allmacdarr = get_macd(chart.alldifarr.clone(), chart.alldeaarr.clone());
	}
}

/*
* Calculate maximum and minimum values
* chart:Chart
*/
pub fn calculate_chart_max_min(chart:&mut FCChart){
    let data_len = chart.data.len() as i32;
    chart.candle_max = 0.0;
    chart.candle_min = 0.0;
    chart.vol_max = 0.0;
    chart.vol_min = 0.0;
    chart.ind_min = 0.0;
    chart.ind_min = 0.0;
    let mut is_trend : bool = false;
    if chart.cycle == "trend"{
        is_trend = true;
    }
    let mut first_open : f64 = 0.0;
    if data_len > 0 {
        for i in chart.first_visible_index..(chart.last_visible_index + 1){
            let ui = i as usize;
            if i == chart.first_visible_index{
                if is_trend{
                    chart.candle_max = chart.data[ui].close;
                    chart.candle_min = chart.data[ui].close;  
                    first_open = chart.data[ui].close;
                }else{
                    chart.candle_max = chart.data[ui].high;
                    chart.candle_min = chart.data[ui].low;
                }
                chart.vol_max = chart.data[ui].volume;
                if chart.show_indicator == "MACD"{
                    chart.ind_max = chart.alldifarr[ui];
                    chart.ind_min = chart.alldifarr[ui];
                }
                else if chart.show_indicator == "KDJ"{
                    chart.ind_max = chart.kdj_k[ui];
                    chart.ind_min = chart.kdj_k[ui];
                }
                else if chart.show_indicator == "RSI"{
                    chart.ind_max = chart.rsi1[ui];
                    chart.ind_min = chart.rsi1[ui];
                }
                else if chart.show_indicator == "BIAS"{
                    chart.ind_max = chart.bias1[ui];
                    chart.ind_min = chart.bias1[ui];
                }
                 else if chart.show_indicator == "ROC"{
                    chart.ind_max = chart.roc[ui];
                    chart.ind_min = chart.roc[ui];
                }
                 else if chart.show_indicator == "BOLL"{
                    chart.ind_max = chart.boll_mid[ui];
                    chart.ind_min = chart.boll_mid[ui];
                }
                else if chart.show_indicator == "WR"{
                    chart.ind_max = chart.wr1[ui];
                    chart.ind_min = chart.wr1[ui];
                }else if chart.show_indicator == "CCI"{
                    chart.ind_max = chart.cci[ui];
                    chart.ind_min = chart.cci[ui];
                }else if chart.show_indicator == "BBI"{
                    chart.ind_max = chart.bbi[ui];
                    chart.ind_min = chart.bbi[ui];
                }
                else if chart.show_indicator == "TRIX"{
                    chart.ind_max = chart.trix[ui];
                    chart.ind_min = chart.trix[ui];
                }
                else if chart.show_indicator == "DMA"{
                    chart.ind_max = chart.dma1[ui];
                    chart.ind_min = chart.dma1[ui];
                }
               
            }else{
                if is_trend{
                    if chart.candle_max < chart.data[ui].close{
                        chart.candle_max = chart.data[ui].close;
                    }
                    if chart.candle_min > chart.data[ui].close{
                        chart.candle_min = chart.data[ui].close;
                    }
                }else{
                    if chart.candle_max < chart.data[ui].high{
                        chart.candle_max = chart.data[ui].high;
                    }
                    if chart.candle_min > chart.data[ui].low{
                        chart.candle_min = chart.data[ui].low;
                    }
                }
                if chart.vol_max < chart.data[ui].volume{
                    chart.vol_max = chart.data[ui].volume;
                }   
				if chart.show_indicator == "MACD"{
					if chart.ind_max < chart.alldifarr[ui]{
						chart.ind_max = chart.alldifarr[ui];
					}
					if chart.ind_max < chart.alldeaarr[ui]{
						chart.ind_max = chart.alldeaarr[ui];
					}
					if chart.ind_max < chart.allmacdarr[ui]{
						chart.ind_max = chart.allmacdarr[ui];
					}
					if chart.ind_min > chart.alldifarr[ui]{
						chart.ind_min = chart.alldifarr[ui];
					}
					if chart.ind_min > chart.alldeaarr[ui]{
						chart.ind_min = chart.alldeaarr[ui];
					}
					if chart.ind_min > chart.allmacdarr[ui]{
						chart.ind_min = chart.allmacdarr[ui];
					}
				}else if chart.show_indicator == "KDJ"{
					if chart.ind_max < chart.kdj_k[ui]{
						chart.ind_max = chart.kdj_k[ui];
					}
					if chart.ind_max < chart.kdj_d[ui]{
						chart.ind_max = chart.kdj_d[ui];
					}
					if chart.ind_max < chart.kdj_j[ui]{
						chart.ind_max = chart.kdj_j[ui];
					}
					if chart.ind_min > chart.kdj_k[ui]{
						chart.ind_min = chart.kdj_k[ui];
					}
					if chart.ind_min > chart.kdj_d[ui]{
						chart.ind_min = chart.kdj_d[ui];
					}
					if chart.ind_min > chart.kdj_j[ui]{
						chart.ind_min = chart.kdj_j[ui];
					}
				}else if chart.show_indicator == "RSI"{
					if chart.ind_max < chart.rsi1[ui]{
						chart.ind_max = chart.rsi1[ui];
					}
					if chart.ind_max < chart.rsi2[ui]{
						 chart.ind_max = chart.rsi2[ui];
					}
					if chart.ind_max < chart.rsi3[ui]{
						chart.ind_max = chart.rsi3[ui];
					}
					if chart.ind_min > chart.rsi1[ui]{
						chart.ind_min = chart.rsi1[ui];
					}
					if chart.ind_min > chart.rsi2[ui]{
						chart.ind_min = chart.rsi2[ui];
					}
					if chart.ind_min > chart.rsi3[ui]{
						chart.ind_min = chart.rsi3[ui];
					}
				}else if chart.show_indicator == "BIAS"{
					if chart.ind_max < chart.bias1[ui]{
						chart.ind_max = chart.bias1[ui];
					}
					if chart.ind_max < chart.bias2[ui]{
						chart.ind_max = chart.bias2[ui];
					}
					if chart.ind_max < chart.bias3[ui]{
						chart.ind_max = chart.bias3[ui];
					}
					if chart.ind_min > chart.bias1[ui]{
						chart.ind_min = chart.bias1[ui];
					}
					if chart.ind_min > chart.bias2[ui]{
						chart.ind_min = chart.bias2[ui];
					}
					if chart.ind_min > chart.bias3[ui]{
						chart.ind_min = chart.bias3[ui];
					}
				}else if chart.show_indicator == "ROC"{
					if chart.ind_max < chart. roc[ui]{
						chart.ind_max = chart.roc[ui];
					}
					if chart.ind_max < chart.roc_ma[ui]{
						chart.ind_max = chart.roc_ma[ui];
					}
					if chart.ind_min > chart.roc[ui]{
						chart.ind_min = chart.roc[ui];
					}
					if chart.ind_min > chart.roc_ma[ui]{
						chart.ind_min = chart.roc_ma[ui];
					}
				}else if chart.show_indicator == "BOLL"{
					if chart.ind_max < chart.boll_mid[ui]{
						chart.ind_max = chart.boll_mid[ui];
					}
					if chart.ind_max < chart.boll_up[ui]{
						chart.ind_max = chart.boll_up[ui];
					}
					if chart.ind_max < chart.boll_down[ui]{
						chart.ind_max = chart.boll_down[ui];
					}
					if chart.ind_min > chart.boll_mid[ui]{
						chart.ind_min = chart.boll_mid[ui];
					}
					if chart.ind_min > chart.boll_up[ui]{
						chart.ind_min = chart.boll_up[ui];
					}
					if chart.ind_min > chart.boll_down[ui]{
						chart.ind_min = chart.boll_down[ui];
					}
				}
				else if chart.show_indicator == "WR"{
					if chart.ind_max < chart.wr1[ui]{
						chart.ind_max = chart.wr1[ui];
					}
					if chart.ind_max < chart.wr2[ui]{
						chart.ind_max = chart.wr2[ui];
					}
					if chart.ind_min > chart.wr1[ui]{
						chart.ind_min = chart.wr1[ui];
					}
					if chart.ind_min > chart.wr2[ui]{
						chart.ind_min = chart.wr2[ui];
					}
				}else if chart.show_indicator == "CCI"{
					if chart.ind_max < chart.cci[ui]{
						chart.ind_max = chart.cci[ui];
					}
					if chart.ind_min > chart.cci[ui]{
						chart.ind_min = chart.cci[ui];
					}
				}else if chart.show_indicator == "BBI"{
					if chart.ind_max < chart.bbi[ui]{
						chart.ind_max = chart.bbi[ui];
					}
					if chart.ind_min > chart.bbi[ui]{
						chart.ind_min = chart.bbi[ui];
					}
				}else if chart.show_indicator == "TRIX"{
					if chart.ind_max < chart.trix[ui]{
						chart.ind_max = chart.trix[ui];
					}
					if chart.ind_max < chart.trix_ma[ui]{
						chart.ind_max = chart.trix_ma[ui];
					}
					if chart.ind_min > chart.trix[ui]{
						chart.ind_min = chart.trix[ui];
					}
					if chart.ind_min > chart.trix_ma[ui]{
						chart.ind_min = chart.trix_ma[ui];
					}
				}else if chart.show_indicator == "DMA"{
					if chart.ind_max < chart.dma1[ui]{
						chart.ind_max = chart.dma1[ui];
					}
					if chart.ind_max < chart.dma2[ui]{
						chart.ind_max = chart.dma2[ui];
					}
					if chart.ind_min > chart.dma1[ui]{
						chart.ind_min = chart.dma1[ui];
					}
					if chart.ind_min > chart.dma2[ui]{
						chart.ind_min = chart.dma2[ui];
					}
				}
            }
        }
    }
    if is_trend{
        let mut sub_max : f64 = 0.0;
        let f_value : f64 = (chart.candle_max - first_open).abs();
        let s_value : f64 = (chart.candle_min - first_open).abs();
        if f_value > s_value{
            sub_max = f_value;
        }else{
            sub_max = s_value;
        }
        chart.candle_max = first_open + sub_max;
        chart.candle_min = first_open - sub_max;
    }else{
        if chart.candle_max == 0.0 && chart.candle_min == 0.0 {
            chart.candle_max = 1.0;
            chart.candle_min = -1.0;
        }
        if chart.vol_max == 0.0 && chart.vol_min == 0.0 {
            chart.vol_max = 1.0;
            chart.vol_min = -1.0;
        }
        if chart.ind_max == 0.0 && chart.ind_min == 0.0 {
            chart.ind_max = 1.0;
            chart.ind_min = -1.0;
        }
        if chart.ind_max2 == 0.0 && chart.ind_min2 == 0.0 {
            chart.ind_max2 = 1.0;
            chart.ind_min2 = -1.0;
        }
    }
}

/*
* Touch move method for chart
* chart: Chart
* first_touch:Is it first touch
* first_point:Point of first touch
* second_touch:Is it second touch
* second_point:Point of second touch
*/
pub fn touch_move_chart(chart:&mut FCChart, first_touch:bool, first_point:FCPoint, second_touch:bool, second_point:FCPoint){
    let mp_x = first_point.x;
    let mp_y = first_point.y;   
    let mp_x1 = second_point.x;
    let mp_y2 = second_point.y;
    let mp = FCPoint{x:mp_x, y:mp_y};
    chart.cross_stop_index = get_chart_index(chart, mp);
    let data_len = chart.data.len() as i32;
	if first_touch && chart.splot.vid > 0{
	    let new_index = get_chart_index(chart, FCPoint{x:mp_x, y:mp_y});
	    if new_index >= 0 && new_index < data_len{
	        let new_date = get_chart_date_by_index(chart, new_index);
	        let new_value = get_candle_div_value(chart, FCPoint{x:mp_x, y:mp_y});
            if chart.select_plot_point == 0{
	            chart.splot.key1 = new_date;
                chart.splot.value1 = new_value;
            } else if chart.select_plot_point == 1{
                chart.splot.key2 = new_date;
                chart.splot.value2 = new_value;
            } else if chart.select_plot_point == 2{
                chart.splot.key3 = new_date;
                chart.splot.value3 = new_value;
	        }
            else if chart.start_move_plot{
	            let bvalue = get_candle_div_value(chart, FCPoint{x:chart.touch_down_position.x, y:chart.touch_down_position.y});
	            let bindex = get_chart_index(chart, FCPoint{x:chart.touch_down_position.x, y:chart.touch_down_position.y});
                if chart.splot.key1 > 0.0{
                    chart.splot.value1 = chart.splot.start_value1 + (new_value - bvalue);
                    let start_index1 = get_chart_index_by_date(chart, chart.splot.start_key1);
                    let mut new_index1 = start_index1 + (new_index - bindex);
                    if new_index1 < 0{
                        new_index1 = 0;
                    }
                    else if new_index1 > data_len - 1{
                        new_index1 = data_len - 1;
                    }
                    chart.splot.key1 = get_chart_date_by_index(chart, new_index1);
                }
                if chart.splot.key2 > 0.0{
                    chart.splot.value2 = chart.splot.start_value2 + (new_value - bvalue);
                    let start_index2 = get_chart_index_by_date(chart, chart.splot.start_key2);
                    let mut new_index2 = start_index2 + (new_index - bindex);
                    if new_index2 < 0{
                        new_index2 = 0;
                    }
                    else if new_index2 > data_len - 1{
                        new_index2 = data_len - 1;
                    }
                    chart.splot.key2 = get_chart_date_by_index(chart, new_index2);
                }
                if chart.splot.key3 > 0.0{
                    chart.splot.value3 = chart.splot.start_value3 + (new_value - bvalue);
                    let start_index3 = get_chart_index_by_date(chart, chart.splot.start_key3);
                    let mut new_index3 = start_index3 + (new_index - bindex);
                    if new_index3 < 0{
                        new_index3 = 0;
                    }
                    else if new_index3 > data_len - 1{
                        new_index3 = data_len - 1;
                    }
                    chart.splot.key3 = get_chart_date_by_index(chart, new_index3);
                }
            }
	    }
	    for i in 0..chart.plots.len(){
			let plot = chart.plots[i].clone();
			if plot.vid == chart.splot.vid{
				chart.plots[i] = chart.splot.clone();
				break;
			}
		}
	    return;
	}
	if first_touch && second_touch {
        if first_point.x > second_point.x {
            chart.first_touch_point_cache.x = mp_x1;
            chart.first_touch_point_cache.y = mp_y2;
            chart.second_touch_point_cache.x = mp_x;
            chart.second_touch_point_cache.y = mp_y;
        } else {
            chart.first_touch_point_cache.x = mp_x;
            chart.first_touch_point_cache.y = mp_y;
            chart.second_touch_point_cache.x = mp_x1;
            chart.second_touch_point_cache.y = mp_y2;
        }
        if chart.first_touch_index_cache == -1 || chart.second_touch_index_cache == -1 {
            chart.first_touch_index_cache = get_chart_index(chart, FCPoint{x:chart.first_touch_point_cache.x, y:chart.first_touch_point_cache.y});
            chart.second_touch_index_cache = get_chart_index(chart, FCPoint{x:chart.second_touch_point_cache.x, y:chart.second_touch_point_cache.y});
            chart.first_index_cache = chart.first_visible_index;
            chart.last_index_cache = chart.last_visible_index;
        }
    } else if first_touch {
        chart.second_touch_index_cache = -1;
        if chart.first_touch_index_cache == -1 {
            chart.first_touch_point_cache.x = mp_x;
            chart.first_touch_point_cache.y = mp_y;
            chart.first_touch_index_cache = get_chart_index(chart, FCPoint{x:chart.first_touch_point_cache.x, y:chart.first_touch_point_cache.y});
            chart.first_index_cache = chart.first_visible_index;
            chart.last_index_cache = chart.last_visible_index;
        }
    }

    if first_touch && second_touch {
        if chart.first_touch_index_cache != -1 && chart.second_touch_index_cache != -1 {
            let mut f_point = FCPoint{x:mp_x, y:mp_y};
            let mut s_point = FCPoint{x:mp_x1, y:mp_y2};
            if first_point.x > second_point.x {
                f_point.x = mp_x1;
                f_point.y = mp_y2;
                s_point.x = mp_x;
                s_point.y = mp_y;
            }
            let sub_x = (s_point.x - f_point.x).abs();
            let sub_index = (chart.second_touch_index_cache - chart.first_touch_index_cache).abs();
            if sub_x > 0.0 && sub_index > 0{
                let mut new_scale_pixel = sub_x / (sub_index as f32);
                if new_scale_pixel >= 3.0 {
                    let int_scale_pixel = new_scale_pixel as i32;
                    new_scale_pixel = int_scale_pixel as f32;
                }
                if new_scale_pixel != chart.hscale_pixel {
                    let mut new_first_index = chart.first_touch_index_cache;
                    let mut this_x = f_point.x;
                    this_x = this_x - new_scale_pixel;
                    while this_x > chart.left_vscale_width + new_scale_pixel {
                        new_first_index = new_first_index - 1;
                        if new_first_index < 0 {
                            new_first_index = 0;
                            break;
                        }
                        this_x = this_x - new_scale_pixel;
                    }

                    this_x = s_point.x;
                    let mut new_second_index = chart.second_touch_index_cache;
                    this_x = this_x + new_scale_pixel;
                    while this_x < chart.view.size.cx - chart.right_vscale_width - new_scale_pixel {
                        new_second_index = new_second_index + 1;
                        if new_second_index > data_len {
                            new_second_index = data_len - 1;
                            break;
                        }
                        this_x = this_x + new_scale_pixel;
                    }
                    set_chart_visible_index(chart, new_first_index, new_second_index);
                    let working_area_width = get_chart_workarea_width(chart);
                    let max_visible_record = get_max_visible_count(chart, chart.hscale_pixel, working_area_width);
                    while max_visible_record < chart.last_visible_index - chart.first_visible_index + 1
                          && chart.last_visible_index > chart.first_visible_index {
                        chart.last_visible_index = chart.last_visible_index - 1;
                    }
                    check_chart_last_visible_index(chart);
                    reset_chart_visible_record(chart);
                    calculate_chart_max_min(chart);
                }
            }
        }
    } else if first_touch {
        let mut sub_index = ((chart.first_touch_point_cache.x - first_point.x) / chart.hscale_pixel) as i32;
        if chart.last_visible_index + sub_index > data_len - 1 {
            sub_index = data_len - 1 - chart.last_index_cache;
        } else if chart.first_visible_index + sub_index < 0 {
            sub_index = -chart.first_index_cache;
        }
        chart.first_visible_index = chart.first_index_cache + sub_index;
        chart.last_visible_index = chart.last_index_cache + sub_index;
        check_chart_last_visible_index(chart);
        reset_chart_visible_record(chart);
        calculate_chart_max_min(chart);
    }
}

/*
* Calculate the upper and lower limits of linear regression
* chart:Chart
* plot:Plot
* a:Line parameter k
* b:Line parameter b
* up_sub_value:Up sub value
* down_sub_value:Down sub value
*/
pub fn get_lrband_range(chart:&mut FCChart, plot:&mut FCPlot, a:f32, b:f32, up_sub_value:&mut f64, down_sub_value:&mut f64){
    let mut bindex = get_chart_index_by_date(chart, plot.key1);
    let mut eindex = get_chart_index_by_date(chart, plot.key2);
    let mut temp_bindex : i32 = 0;
	let mut temp_eindex : i32 = 0;
	if bindex > eindex{
		temp_bindex = eindex;
		temp_eindex = bindex;
	}else{
		temp_bindex = bindex;
		temp_eindex = eindex;
	}
    bindex = temp_bindex;
    eindex = temp_eindex;
	let mut high_list: Vec<f64> = Vec::new();
	let mut low_list: Vec<f64> = Vec::new();
	for i in bindex..(eindex + 1){
        let high = chart.data[i as usize].high;
        let low = chart.data[i as usize].low;
        let mid_value = (((i - bindex + 1) as f32) * a + b) as f64;
		high_list.push(high - mid_value);
        low_list.push(mid_value - low);
	}
    *up_sub_value = max_value(high_list);
    *down_sub_value = max_value(low_list);
}

/*
* Zoom out chart
* chart:Chart
*/
pub fn zoomout_chart(chart:&mut FCChart){
    if !chart.auto_fill_hscale {
        let mut h_scale_pixel = chart.hscale_pixel;
        let old_x = get_chart_x(chart, chart.cross_stop_index);
        let pure_h = get_chart_workarea_width(chart);
        let mut ori_max : i32 = -1;
        let mut max : i32 = -1;
        let mut deal : i32 = 0;
        let data_count = chart.data.len() as i32;
        let mut findex = chart.first_visible_index;
        let mut lindex = chart.last_visible_index;
        if h_scale_pixel < pure_h {
            ori_max = get_max_visible_count(chart, h_scale_pixel, pure_h);
            if data_count < ori_max {
                deal = 1;
            }
            if h_scale_pixel > 3.0 {
                h_scale_pixel = h_scale_pixel + 1.0;
            } else {
                if h_scale_pixel == 1.0 {
                    h_scale_pixel = 2.0;
                } else {
                    h_scale_pixel = h_scale_pixel * 1.5;
                    if h_scale_pixel > 3.0 {
                        h_scale_pixel = (h_scale_pixel as i32) as f32;
                    }
                }
            }
            max = get_max_visible_count(chart, h_scale_pixel, pure_h);
            if data_count >= max {
                if deal == 1{
                    lindex = data_count - 1;
                }
                findex = lindex - max + 1;
                if findex < 0 {
                    findex = 0;
                }
            }
        }
        chart.hscale_pixel = h_scale_pixel;
        chart.first_visible_index = findex;
        chart.last_visible_index = lindex;
        if chart.show_cross_line{
            let mut new_x = get_chart_x(chart, chart.cross_stop_index);
            if new_x > old_x {
                while chart.last_visible_index < data_count - 1{
                    chart.first_visible_index = chart.first_visible_index + 1;
                    chart.last_visible_index = chart.last_visible_index + 1;
                    new_x = get_chart_x(chart, chart.cross_stop_index);
                    if new_x <= old_x{
                        break;
                    }
                }

            }
            else if new_x < old_x{
                while chart.first_visible_index > 0{
                    chart.first_visible_index = chart.first_visible_index - 1;
                    chart.last_visible_index = chart.last_visible_index - 1;
                    new_x = get_chart_x(chart, chart.cross_stop_index);
                    if new_x >= old_x{
                        break;
                    }
                }
            }
        }
        check_chart_last_visible_index(chart);
        calculate_chart_max_min(chart);
    }
}

/*
* Zoom in chart
* chart:Chart
*/
pub fn zoomin_chart(chart:&mut FCChart){
     if !chart.auto_fill_hscale {
        let mut h_scale_pixel = chart.hscale_pixel;
        let old_x = get_chart_x(chart, chart.cross_stop_index);
        let pure_h = get_chart_workarea_width(chart);
        let mut max : i32 = -1;
        let data_count = chart.data.len() as i32;
        let mut findex = chart.first_visible_index;
        let mut lindex = chart.last_visible_index;
        if h_scale_pixel > 3.0 {
            h_scale_pixel -= 1.0;
        } else {
            h_scale_pixel = h_scale_pixel * 2.0 / 3.0;
            if h_scale_pixel > 3.0 {
                 h_scale_pixel = (h_scale_pixel as i32) as f32;
            }
        }
        max = get_max_visible_count(chart, h_scale_pixel, pure_h);
        if max >= data_count {
            if h_scale_pixel < 1.0 {
                h_scale_pixel = pure_h / (max as f32);
            }
            findex = 0;
            lindex = data_count - 1;
        } else {
            findex = lindex - max + 1;
            if findex < 0 {
                findex = 0;
            }
        }
        chart.hscale_pixel = h_scale_pixel;
        chart.first_visible_index = findex;
        chart.last_visible_index = lindex;
        if chart.show_cross_line{
            let mut new_x = get_chart_x(chart, chart.cross_stop_index);
            if new_x > old_x{
                while chart.last_visible_index < data_count - 1{
                    chart.first_visible_index = chart.first_visible_index + 1;
                    chart.last_visible_index = chart.last_visible_index + 1;
                    new_x = get_chart_x(chart, chart.cross_stop_index);
                    if new_x <= old_x
                    {
                        break;
                    }
                }

            }
            else if new_x < old_x{
                while chart.first_visible_index > 0{
                    chart.first_visible_index = chart.first_visible_index - 1;
                    chart.last_visible_index = chart.last_visible_index - 1;
                    new_x = get_chart_x(chart, chart.cross_stop_index);
                    if new_x >= old_x{
                        break;
                    }
                }
            }
        }
        check_chart_last_visible_index(chart);
        calculate_chart_max_min(chart);
    }
}

/**
 * Calculate minimum value
 * ticks: Lowest price array
 * days:N
 */
pub fn llv_value(ticks:Vec<f64>, days:i32)->Vec<f64>{
    let mut llv: Vec<f64> = Vec::new();
    let min = ticks[0];
    for i in 0..ticks.len(){
		let mut min : f64 = 0.0;
		if (i as i32) >= days {
			min = ticks[i as usize];
            let mut j = i as i32;
            while j > (i as i32) - days{
                if min > ticks[j as usize] {
					min = ticks[j as usize];
				}
                j = j - 1;
            }
			llv.push(min);
		} else {
			if min > ticks[i as usize] {
				min = ticks[i as usize];
			}
			llv.push(min);
		}
	}
    return llv;
}

/**
 * Calculate maximum value
 * ticks: Lowest price array
 * days:N
 */
pub fn hhv_value(ticks:Vec<f64>, days:i32)->Vec<f64>{
    let mut hhv: Vec<f64> = Vec::new();
	let max = ticks[0];
	for i in 0..ticks.len(){
		let mut max : f64 = 0.0;
		if (i as i32) >= days{
			max = ticks[i as usize];
			let mut j = i as i32;
            while j > (i as i32) - days{
                if max < ticks[j as usize] {
					max = ticks[j as usize];
				}
                j = j - 1;
            }
			hhv.push(max);
		} else {
			if max > ticks[i as usize] {
				max = ticks[i as usize];
			}
			hhv.push(max);
		}
	}
	return hhv;
}

/**
 * Obtain the previous day's value
 * ticks: Lowest price array
 * days:N
 */
pub fn ref_value(ticks:Vec<f64>, days:i32)->Vec<f64>{
    let mut ref_arr: Vec<f64> = Vec::new();
	let length = ticks.len();
    for i in 0..length{
		let mut ref_value : f64 = 0.0;
		if (i as i32) >= days {
			ref_value = ticks[(i as i32 - days) as usize];
		} else {
			ref_value = ticks[0];
		}
		ref_arr.push(ref_value);
	}
	return ref_arr;
}

/**
 * Calculate ema
 * n: N
 * value: Value
 * last_ema:Last ema
 */
pub fn get_ema(n:i32, value:f64, last_ema:f64)->f64{
    return (value * 2.0 + last_ema * ((n - 1) as f64)) / ((n + 1) as f64);
}

/**
 * Calculate macd
 * dif: Dif collection
 * dea: Dea collection
 */
pub fn get_macd(dif:Vec<f64>, dea:Vec<f64>)->Vec<f64>{
    let mut result: Vec<f64> = Vec::new();
    for i in 0..dif.len(){
			result.push((dif[i as usize] - dea[i as usize]) * 2.0);
    }
    return result;
}

/**
 * Obtain the numerical value of dif
 * close12: Close 12 collection
 * close26: Close 26 collection
 */
pub fn get_dif(close12:Vec<f64>, close26:Vec<f64>)->Vec<f64>{
	let mut result : Vec<f64> = Vec::new();
	for i in 0..close12.len(){
		result.push(close12[i] - close26[i]);
	}
	return result;
}

/**
 * Calculate the boll indicator
 */
pub fn get_boll_data(ticks:Vec<f64>, ma_days:i32, ups:&mut Vec<f64>, mas:&mut Vec<f64>, lows:&mut Vec<f64>){
	let tick_begin = ma_days - 1;
	let mut ma_sum : f64= 0.0;
	let mut p : f64 = 0.0;
    for i in 0..ticks.len(){
		let c = ticks[i as usize];
        let mut ma : f64 = 0.0;
        let mut md : f64 = 0.0;
        let mut bstart : i32 = 0;
        let mut md_sum : f64 = 0.0;
		ma_sum = ma_sum + c;
        if (i as i32) >= tick_begin {
			ma_sum = ma_sum - p;
			ma = ma_sum / (ma_days as f64);
			bstart = (i as i32) - tick_begin;
			p = ticks[bstart as usize];
			mas.push(ma);
			bstart = (i as i32) - tick_begin;
			p = ticks[bstart as usize];
			let mut values:Vec<f64> = Vec::new();
			for j in bstart..(bstart + ma_days){
				values.push(ticks[j as usize]);
			}
			md_sum = standard_deviation_sum(values.clone(), ma, 2.0);
			md = (md_sum / (ma_days as f64)).sqrt();
			ups.push(ma + 2.0 * md);
			lows.push(ma - 2.0 * md);
		} else {
			ma = ma_sum / ((i + 1) as f64);
			mas.push(ma);
			let mut values:Vec<f64> = Vec::new();
			for j in 0..(i + 1){
				values.push(ticks[j as usize]);
			}
			md_sum = standard_deviation_sum(values.clone(), ma, 2.0);
			md = (md_sum / (i + 1) as f64).sqrt();
			ups.push(ma + 2.0 * md);
			lows.push(ma - 2.0 * md);
		}
	}
}

/*
* Obtain the range of maximum and minimum values
* high_arr:High collection
* low_arr:Low collection
* max_high:Max high
* min_low:Min low
*/
pub fn get_max_high_and_min_low(high_arr:Vec<f64>, low_arr:Vec<f64>, max_high:&mut f64, min_low:&mut f64){
    for i in 0..low_arr.len(){
        let high = high_arr[i as usize];
		let low = low_arr[i as usize];
		if high > *max_high {
			*max_high = high;
		}
		if low < *min_low {
			*min_low = low;
		}
    }
}

/**
 * Calculate the kdj indicator
 */
pub fn get_kdj_data(high_arr:Vec<f64>, low_arr:Vec<f64>, close_arr:Vec<f64>, n:i32, m1:i32, m2:i32, ks:&mut Vec<f64>, ds:&mut Vec<f64>, js:&mut Vec<f64>){
    let days : i32 = n;
    let mut rsvs: Vec<f64> = Vec::new();
    let mut last_k : f64 = 0.0;
    let mut last_d : f64 = 0.0;
    let mut cur_k : f64 = 0.0;
    let mut cur_d : f64 = 0.0;
    for i in 0..high_arr.len(){
        let mut high_list: Vec<f64> = Vec::new();
        let mut low_list: Vec<f64> = Vec::new();
        let mut start_index : i32 = i as i32 - days;
        if start_index < 0{
            start_index = 0;
        }
        for j in start_index..((i + 1) as i32){
            high_list.push(high_arr[j as usize]);
            low_list.push(low_arr[j as usize]);
        }
        let mut max : f64 = 0.0;
        let mut min : f64 = 0.0;
        let close = close_arr[i as usize];
        get_max_high_and_min_low(high_list.to_vec(), low_list.to_vec(), &mut max, &mut min);
        if max == min {
			rsvs.push(0.0);
		} else {
			rsvs.push((close - min) / (max - min) * 100.0);
		}
		if i == 0 {
			last_k = rsvs[i as usize];
            last_d = rsvs[i as usize];
		}
		cur_k = (m1 as f64 - 1.0) / m1 as f64 * last_k + 1.0 / m1 as f64 * rsvs[i as usize];
		ks.push(cur_k);
		last_k = cur_k;

		cur_d = (m2 as f64 - 1.0) / m2 as f64 * last_d + 1.0 / m2 as f64 * cur_k;
		ds.push(cur_d);
		last_d = cur_d;

		js.push(3.0 * cur_k - 2.0 * cur_d);
    }
}

/**
 * Calculate the rsi indicator
 */
pub fn get_rsi_data(ticks:Vec<f64>, n1:i32, n2:i32, n3:i32, rsi1:&mut Vec<f64>, rsi2:&mut Vec<f64>, rsi3:&mut Vec<f64>){
    let mut last_close_px = ticks[0];
    let mut last_sm1: f64 = 0.0;
    let mut last_sa1 : f64 = 0.0;
    let mut last_sm2: f64 = 0.0;
    let mut last_sa2 : f64 = 0.0;
    let mut last_sm3: f64 = 0.0;
    let mut last_sa3 : f64 = 0.0;
    for i in 0..ticks.len(){
        let c = ticks[i as usize];
		let m = (c - last_close_px).max(0.0);
		let a = (c - last_close_px).abs();
        if i == 0{
            last_sm1 = 0.0;
            last_sa1 = 0.0;
            rsi1.push(0.0);
        }else{
            last_sm1 = (m + ((n1 - 1) as f64) * last_sm1) / (n1 as f64);
		    last_sa1 = (a + ((n1 - 1) as f64) * last_sa1)/ (n1 as f64);
            if last_sa1 != 0.0 {
                rsi1.push(last_sm1 / last_sa1 * 100.0);
			} else {
				rsi1.push(0.0);
			}
        }

         if i == 0{
            last_sm2 = 0.0;
            last_sa2 = 0.0;
            rsi2.push(0.0);
        }else{
            last_sm2 = (m + ((n2 - 1) as f64) * last_sm2) / (n2 as f64);
		    last_sa2 = (a + ((n2 - 1) as f64) * last_sa2)/ (n2 as f64);
            if last_sa2 != 0.0 {
                rsi2.push(last_sm2 / last_sa2 * 100.0);
			} else {
				rsi2.push(0.0);
			}
        }

         if i == 0{
            last_sm3 = 0.0;
            last_sa3 = 0.0;
            rsi3.push(0.0);
        }else{
            last_sm3 = (m + ((n3 - 1) as f64) * last_sm3) / (n3 as f64);
		    last_sa3 = (a + ((n3 - 1) as f64) * last_sa3)/ (n3 as f64);
            if last_sa3 != 0.0 {
                rsi3.push(last_sm3 / last_sa3 * 100.0);
			} else {
				rsi3.push(0.0);
			}
        }
        last_close_px =  c;
    }
}

/**
 * Calculate the moving average
 * ticks:Value collection
 * days:N
 */
pub fn ma_value(ticks:Vec<f64>, days:i32)->Vec<f64>{
    let mut ma_sum : f64 = 0.0;
	let mut mas: Vec<f64> = Vec::new();
	let mut last : f64 = 0.0;
	for i in 0..ticks.len(){
		let mut ma : f64 = 0.0;
		if (i as i32) >= days {
			last = ticks[(i as i32 - days) as usize];
			ma_sum = ma_sum + ticks[i as usize] - last;
			ma = ma_sum / (days as f64);
		} else {
			ma_sum = ma_sum + ticks[i as usize];
			ma = ma_sum / ((i + 1) as f64);
		}
		mas.push(ma);
	}
	return mas;
}

/**
 * Calculate the roc indicator
 */
pub fn get_roc_data(ticks:Vec<f64>, n:i32, m:i32, roc:&mut Vec<f64>, maroc:&mut Vec<f64>){
	for i in 0..ticks.len(){
		let mut curr_roc : f64 = 0.0;
		if (i as i32) >= n {
			curr_roc = 100.0 * (ticks[i as usize] - ticks[(i as i32 - n) as usize]) / ticks[(i as i32 - n) as usize];
			roc.push(curr_roc);
		} else {
			curr_roc = 100.0 * (ticks[i as usize] - ticks[0]) / ticks[0];
			roc.push(curr_roc);
		}
	}
	let ma_result = ma_value(roc.to_vec(), m);
    for i in 0..ma_result.len(){
        maroc.push(ma_result[i as usize]);
    }
}

/**
 * Calculate the bias indicator
 */
pub fn get_bias_data(ticks:Vec<f64>, n1:i32, n2:i32, n3:i32, bias1_arr:&mut Vec<f64>, bias2_arr:&mut Vec<f64>, bias3_arr:&mut Vec<f64>){
    let ma1 = ma_value(ticks.to_vec(), n1);
	let ma2 = ma_value(ticks.to_vec(), n2);
	let ma3 = ma_value(ticks.to_vec(), n3);
	for i in 0..ticks.len(){
		let mut b1 : f64 = 0.0;
        let mut b2 : f64 = 0.0;
        let mut b3 : f64 = 0.0;
        let ui = i as usize;
		b1 = (ticks[ui] - ma1[ui]) / ma1[ui] * 100.0;
		b2 = (ticks[ui] - ma2[ui]) / ma2[ui] * 100.0;
		b3 = (ticks[ui] - ma3[ui]) / ma3[ui] * 100.0;
		bias1_arr.push(b1);
		bias2_arr.push(b2);
		bias3_arr.push(b3);
	}
}

/**
 * Calculate the dma indicator
 */
pub fn get_dma_data(ticks:Vec<f64>, n1:i32, n2:i32, dif_arr:&mut Vec<f64>, difma_arr:&mut Vec<f64>){
	let ma10 = ma_value(ticks.to_vec(), n1);
	let ma50 = ma_value(ticks.to_vec(), n2);
	for i in 0..ticks.len(){
		let dif = ma10[i as usize] - ma50[i as usize];
		dif_arr.push(dif);
	}
    let ma_result = ma_value(dif_arr.to_vec(), n1);
    for i in 0..ma_result.len(){
        difma_arr.push(ma_result[i as usize]);
    }
}

/**
 * Calculate the bbi indicator
 */
pub fn get_bbi_data(ticks:Vec<f64>, n1:i32, n2:i32, n3:i32, n4:i32, bbi_arr:&mut Vec<f64>){
    let ma3 = ma_value(ticks.to_vec(), n1);
	let ma6 = ma_value(ticks.to_vec(), n2);
	let ma12 = ma_value(ticks.to_vec(), n3);
	let ma24 = ma_value(ticks.to_vec(), n4);
	for i in 0..ticks.len(){
        let ui = i as usize;
		let bbi = (ma3[ui] + ma6[ui] + ma12[ui] + ma24[ui]) / 4.0;
		bbi_arr.push(bbi);
	}
}

/**
 * Calculate the wr indicator
 */
pub fn get_wr_data(high_arr:Vec<f64>, low_arr:Vec<f64>, close_arr:Vec<f64>, n1:i32, n2:i32, wr1_arr:&mut Vec<f64>, wr2_arr:&mut Vec<f64>){
	let high_arr1 = hhv_value(high_arr.to_vec(), n1);
	let high_arr2 = hhv_value(high_arr.to_vec(), n2);
	let low_arr1 = llv_value(low_arr.to_vec(), n1);
	let low_arr2 = llv_value(low_arr.to_vec(), n2);
	for i in 0..close_arr.len(){
        let ui = i as usize;
		let high1 = high_arr1[ui];
		let low1 = low_arr1[ui];
		let high2 = high_arr2[ui];
		let low2 = low_arr2[ui];
		let close = close_arr[ui];
		let wr1 = 100.0 * (high1 - close) / (high1 - low1);
		let wr2 = 100.0 * (high2 - close) / (high2 - low2);
		wr1_arr.push(wr1);
		wr2_arr.push(wr2);
	}
}

/**
 * Calculate the cci indicator
 */
pub fn get_cci_data(high_arr:Vec<f64>, low_arr:Vec<f64>, close_arr:Vec<f64>, n:i32, cci_arr:&mut Vec<f64>){
    let mut tp_arr: Vec<f64> = Vec::new();
	for i in 0..close_arr.len(){
        let iu = i as usize;
		tp_arr.push((high_arr[iu] + low_arr[iu] + close_arr[iu]) / 3.0);
	}
	let ma_close = ma_value(close_arr.to_vec(), n);
    let mut md_arr: Vec<f64> = Vec::new();
	for i in 0..close_arr.len(){
		md_arr.push(ma_close[i as usize] - close_arr[i as usize]);
	}
	let ma_md = ma_value(md_arr.to_vec(), n);
	for i in 0..close_arr.len(){
        let iu = i as usize;
		let mut cci:f64 = 0.0;
		if ma_md[iu] != 0.0{
			cci = (tp_arr[iu] - ma_close[iu]) / (ma_md[iu] * 0.015);
		}
		cci_arr.push(cci);
	}
}

/**
 * Calculate the trix indicator
 */
pub fn get_trix_data(ticks:Vec<f64>, n:i32, m:i32, trix_arr:&mut Vec<f64>, matrix_arr:&mut Vec<f64>){
    let mut mtr_arr: Vec<f64> = Vec::new();
    let mut ema_arr1: Vec<f64> = Vec::new();
	ema_arr1.push(ticks[0]);
    for i in 1..ticks.len(){
		ema_arr1.push(get_ema(n, ticks[i as usize], ema_arr1[(i as i32 - 1) as usize]));
	}

    let mut ema_arr2: Vec<f64> = Vec::new();
	ema_arr2.push(ema_arr1[0]);
    for i in 1..ticks.len(){
		ema_arr2.push(get_ema(n, ema_arr1[i as usize], ema_arr2[(i as i32 - 1) as usize]));
	}

	mtr_arr.push(ema_arr2[0]);
	for i in 1..ticks.len(){
		mtr_arr.push(get_ema(n, ema_arr2[i as usize], mtr_arr[(i as i32 - 1) as usize]));
	}

	let ref_value = ref_value(mtr_arr.to_vec(), 1);
	for i in 0..ticks.len(){
        let iu = i as usize;
		let trix = 100.0 * (mtr_arr[iu] - ref_value[iu]) / ref_value[iu];
		trix_arr.push(trix);
	}
    let ma_result = ma_value(trix_arr.to_vec(), m);
    for i in 0..ma_result.len(){
        matrix_arr.push(ma_result[i as usize]);
    }
}

/*
* Obtain the scale of the percentage line
* y1: Y1
* y2: Y2
*/
pub fn get_percent_params(y1:f32, y2:f32)->Vec<f32>{
    let mut y0 : f32 = 0.0;
    let mut y25 : f32 = 0.0;
    let mut y50 : f32 = 0.0;
    let mut y75 : f32 = 0.0;
    let mut y100 : f32 = 0.0;
    y0 = y1;
    if y1 <= y2{
        y25 = y1 + (y2 - y1) / 4.0;
        y50 = y1 + (y2 - y1) / 2.0;
        y75 = y1 + (y2 - y1) * 3.0 / 4.0;
    }else{
        y25 = y2 + (y1 - y2) * 3.0 / 4.0;
        y50 = y2 + (y1 - y2) / 2.0;
        y75 = y2 + (y1 - y2) / 4.0;
    }
    y100 = y2;
    let mut list: Vec<f32> = Vec::new();
    list.push(y0);
    list.push(y25);
    list.push(y50);
    list.push(y75);
    list.push(y100);
    return list;
}

/*
* Select plot
* chart: Chart
* mp:Coordinate
*/
pub fn select_plot(chart:&mut FCChart, mp:FCPoint)->FCPlot{
    chart.start_move_plot = false;
    chart.select_plot_point = -1;
    let plot_point_size : f32 = 5.0;
    let mut splot:FCPlot = FCPlot::new();
    for i in 0..chart.plots.len(){
		let mut plot = chart.plots[i].clone();
        let mut index1 : i32 = 0;
        let mut index2 : i32 = 0;
        let mut index3 : i32 = 0;
        let mut mpx1 : f32 = 0.0;
        let mut mpy1 : f32 = 0.0;
        let mut mpx2 : f32 = 0.0;
        let mut mpy2 : f32 = 0.0;
        let mut mpx3 : f32 = 0.0;
        let mut mpy3 : f32 = 0.0;
        if plot.key1 > 0.0{
            index1 = get_chart_index_by_date(chart, plot.key1);
            mpx1 = get_chart_x(chart, index1);
            mpy1 = get_chart_y(chart, 0, plot.value1);
            if mp.x >= mpx1 - plot_point_size && mp.x <= mpx1 + plot_point_size && mp.y >= mpy1 - plot_point_size && mp.y <= mpy1 + plot_point_size{
                splot = plot.clone();
                chart.select_plot_point = 0;
                break;
            }
        }
        if plot.key2 > 0.0{
            index2 = get_chart_index_by_date(chart, plot.key2);
            mpx2 = get_chart_x(chart, index2);
            mpy2 = get_chart_y(chart, 0, plot.value2);
            if mp.x >= mpx2 - plot_point_size && mp.x <= mpx2 + plot_point_size && mp.y >= mpy2 - plot_point_size && mp.y <= mpy2 + plot_point_size{
                splot = plot.clone();
                chart.select_plot_point = 1;
                break;
            }
        }
        if plot.key3 > 0.0{
            index3 = get_chart_index_by_date(chart, plot.key3);
            mpx3 = get_chart_x(chart, index3);
            mpy3 = get_chart_y(chart, 0, plot.value3);
            if mp.x >= mpx3 - plot_point_size && mp.x <= mpx3 + plot_point_size && mp.y >= mpy3 - plot_point_size && mp.y <= mpy3 + plot_point_size{
                splot = plot.clone();
                chart.select_plot_point = 2;
                break;
            }
        }
        if chart.select_plot_point == -1{
            if plot.plot_type == "Line"{
                chart.start_move_plot = select_line(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx2, mpy2);
            }
            else if plot.plot_type == "AngleLine"{
                chart.start_move_plot = select_line(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx2, mpy2);
                if !chart.start_move_plot{
                    chart.start_move_plot = select_line(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx3, mpy3);
                }
            }
            else if plot.plot_type == "Parallel"{
                chart.start_move_plot = select_line(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx2, mpy2);
                if !chart.start_move_plot{
                    let mut k : f32 = 0.0;
                    let mut b : f32 = 0.0;
                    line_xy(mpx1, mpy1, mpx2, mpy2, 0.0, 0.0, &mut k, &mut b);
                    let new_b = mpy3 - k * mpx3;
                    if mpx2 == mpx1{
                        if mp.x >= mpx3 - plot_point_size && mp.x <= mpx3 + plot_point_size{
                            chart.start_move_plot = true;
                        }
                    }else{
                        let new_x1 = chart.left_vscale_width;
                        let new_y1 = new_x1 * k + new_b;
                        let new_x2 = chart.view.size.cx - chart.right_vscale_width;
                        let new_y2 = new_x2 * k + new_b;
                        chart.start_move_plot = select_line(FCPoint{x:mp.x, y:mp.y}, new_x1, new_y1, new_x2, new_y2);
                    }
                }
            }
            else if plot.plot_type == "LRLine"{
                chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx2, mpy2);
            }
            else if plot.plot_type == "Segment"{
                chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx2, mpy2);
            }else if plot.plot_type == "Ray"{
                chart.start_move_plot = select_ray(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx2, mpy2);
            }
            else if plot.plot_type == "Triangle"{
                chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx2, mpy2);
                if !chart.start_move_plot{
                    chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx2, mpy2, mpx3, mpy3);
                }
                if !chart.start_move_plot{
                    chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx3, mpy3);
                }
            }
            else if plot.plot_type == "Rect"{
                let s_x1 : f32 = mpx1.min(mpx2);
                let s_y1 : f32 = mpy1.min(mpy2);
                let s_x2 : f32 = mpx1.max(mpx2);
                let s_y2 : f32 = mpy1.max(mpy2);
                chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, s_x1, s_y1, s_x2, s_y1);
                if !chart.start_move_plot{
                    chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, s_x2, s_y1, s_x2, s_y2);
                }
                if !chart.start_move_plot{
                    chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, s_x1, s_y2, s_x2, s_y2);
                }
                if !chart.start_move_plot{
                    chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, s_x1, s_y1, s_x1, s_y2);
                }
            }
            else if plot.plot_type == "BoxLine"{
                let s_x1 : f32 = mpx1.min(mpx2);
                let s_y1 : f32 = mpy1.min(mpy2);
                let s_x2 : f32 = mpx1.max(mpx2);
                let s_y2 : f32 = mpy1.max(mpy2);
                chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, s_x1, s_y1, s_x2, s_y1);
                if !chart.start_move_plot{
                    chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, s_x2, s_y1, s_x2, s_y2);
                }
                if !chart.start_move_plot{
                    chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, s_x1, s_y2, s_x2, s_y2);
                }
                if !chart.start_move_plot{
                    chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, s_x1, s_y1, s_x1, s_y2);
                }
            }
            else if plot.plot_type == "TironeLevels"{
                let s_x1 : f32 = mpx1.min(mpx2);
                let s_y1 : f32 = mpy1.min(mpy2);
                let s_x2 : f32 = mpx1.max(mpx2);
                let s_y2 : f32 = mpy1.max(mpy2);
                chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, s_x1, s_y1, s_x2, s_y1);
                if !chart.start_move_plot{
                    chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, s_x1, s_y2, s_x2, s_y2);
                }
            }
            else if plot.plot_type == "GoldenRatio"{
                let s_x1 : f32 = mpx1.min(mpx2);
                let s_y1 : f32 = mpy1.min(mpy2);
                let s_x2 : f32 = mpx1.max(mpx2);
                let s_y2 : f32 = mpy1.max(mpy2);
                let mut ranges: Vec<f32> = Vec::new();
                ranges.push(0.0);
                ranges.push(0.236);
                ranges.push(0.382);
                ranges.push(0.5);
                ranges.push(0.618);
                ranges.push(0.809);
                ranges.push(1.0);
                ranges.push(1.382);
                ranges.push(1.618);
                ranges.push(2.0);
                ranges.push(2.382);
                ranges.push(2.618);
                let min_value = plot.value1.min(plot.value2);
                let max_value = plot.value1.max(plot.value2);
                for j in 0..ranges.len(){
                    let mut new_y : f32 = 0.0;
                    if s_y1 <= s_y2{
                        new_y = s_y1 + (s_y2 - s_y1) * ranges[j as usize];
                    }else{
                        new_y = s_y2 + (s_y1 - s_y2) * (1.0 - ranges[j as usize]);
                    }
                    chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, chart.left_vscale_width, new_y, chart.view.size.cx - chart.right_vscale_width, new_y);
                    if chart.start_move_plot{
                        break;
                    }
                }
            }
            else if plot.plot_type == "Cycle"{
                let r = ((mpx2 - mpx1) * (mpx2 - mpx1) + (mpy2 - mpy1) * (mpy2 - mpy1)).abs().sqrt();
                let round = (mp.x - mpx1) * (mp.x - mpx1) + (mp.y - mpy1) * (mp.y - mpy1);
                if round / (r * r) >= 0.9 && round / (r * r) <= 1.1{
                    chart.start_move_plot = true;
                }
            }else if plot.plot_type == "CircumCycle"{
                let mut o_x : f32 = 0.0;
                let mut o_y : f32 = 0.0;
                let mut r : f32 = 0.0;
                ellipse_or(mpx1, mpy1, mpx2, mpy2, mpx3, mpy3, &mut o_x, &mut o_y, &mut r);
                let round = (mp.x - o_x) * (mp.x - o_x) + (mp.y - o_y) * (mp.y - o_y);
                if round / (r * r) >= 0.9 && round / (r * r) <= 1.1{
                    chart.start_move_plot = true;
                }
            }
            else if plot.plot_type == "Ellipse"{
                let mut x1 : f32 = 0.0;
                let mut y1 : f32 = 0.0;
                let mut x2 : f32 = 0.0;
                let mut y2 : f32 = 0.0;
                if mpx1 <= mpx2{
                    x1 = mpx2;
                    y1 = mpy2;
                    x2 = mpx1;
                    y2 = mpy1;
                }else{
                    x1 = mpx1;
                    y1 = mpy1;
                    x2 = mpx2;
                    y2 = mpy2;
                }
                let x = x1 - (x1 - x2);
                let mut y : f32 = 0.0;
                let width = (x1 - x2) * 2.0;
                let mut height : f32 = 0.0;
                if y1 >= y2{
                    height = (y1 - y2) * 2.0;
                }
                else{
                    height = (y2 - y1) * 2.0;
                }
                y = y2 - height / 2.0;
                let a = width / 2.0;
                let b = height / 2.0;
                chart.start_move_plot = ellipse_has_point(mp.x, mp.y, x + (width / 2.0), y + (height / 2.0), a, b);
            }else if plot.plot_type == "LRBand"{
                chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx2, mpy2);
                if !chart.start_move_plot{
                    let mut list: Vec<f64> = Vec::new();
                    let min_index = index1.min(index2);
                    let max_index = index1.max(index2);
                    for j in min_index..(max_index + 1){
                        list.push(chart.data[j as usize].close);
                    }
                    let mut rk : f32 = 0.0;
                    let mut rb : f32 = 0.0;
                    linear_regression_equation(list, &mut rk, &mut rb);
                    let mut up_sub_value : f64 = 0.0;
                    let mut down_sub_value : f64 = 0.0;
                    get_lrband_range(chart, &mut plot, rk, rb, &mut up_sub_value, &mut down_sub_value);
                    mpy1 = get_chart_y(chart, 0, plot.value1 + up_sub_value);
                    mpy2 = get_chart_y(chart, 0, plot.value2 + up_sub_value);
                    chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx2, mpy2);
                    if !chart.start_move_plot{
                        mpy1 = get_chart_y(chart, 0, plot.value1 - down_sub_value);
                        mpy2 = get_chart_y(chart, 0, plot.value2 - down_sub_value);
                        chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx2, mpy2);
                    }
                }
            }else if plot.plot_type == "LRChannel"{
                let mut k : f32 = 0.0;
                let mut b : f32 = 0.0;
                line_xy(mpx1, mpy1, mpx2, mpy2, 0.0, 0.0, &mut k, &mut b);
                let right_x = chart.view.size.cx - chart.right_vscale_width;
                let mut right_y = right_x * k + b;
                chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, right_x, right_y);
                if !chart.start_move_plot{
                    let mut list: Vec<f64> = Vec::new();
                    let min_index = index1.min(index2);
                    let max_index = index1.max(index2);
                    for j in min_index..(max_index + 1){
                        list.push(chart.data[j as usize].close);
                    }
                    let mut rk : f32 = 0.0;
                    let mut rb : f32 = 0.0;
                    linear_regression_equation(list, &mut rk, &mut rb);
                    let mut up_sub_value : f64 = 0.0;
                    let mut down_sub_value : f64 = 0.0;
                    get_lrband_range(chart, &mut plot, rk, rb, &mut up_sub_value, &mut down_sub_value);
                    mpy1 = get_chart_y(chart, 0, plot.value1 + up_sub_value);
                    mpy2 = get_chart_y(chart, 0, plot.value2 + up_sub_value);
                    line_xy(mpx1, mpy1, mpx2, mpy2, 0.0, 0.0, &mut k, &mut b);
                    right_y = right_x * k + b;
                    chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, right_x, right_y);
                    if !chart.start_move_plot{
                        mpy1 = get_chart_y(chart, 0, plot.value1 - down_sub_value);
                        mpy2 = get_chart_y(chart, 0, plot.value2 - down_sub_value);
                        line_xy(mpx1, mpy1, mpx2, mpy2, 0.0, 0.0, &mut k, &mut b);
                        right_y = right_x * k + b;
                        chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, right_x, right_y);
                    }
                }
            }else if plot.plot_type == "ParalleGram"{
                let mut x4 : f32 = 0.0;
                let mut y4 : f32 = 0.0;
                parallelogram(mpx1, mpy1, mpx2, mpy2, mpx3, mpy3, &mut x4, &mut y4);
                chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx2, mpy2);
                if !chart.start_move_plot{
                    chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx2, mpy2, mpx3, mpy3);
                    if !chart.start_move_plot{
                        chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx3, mpy3, x4, y4);
                        if !chart.start_move_plot{
                            chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, x4, y4, mpx1, mpy1);
                        }
                    }
                }
            }
            else if plot.plot_type == "SpeedResist"{
                chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx2, mpy2);
                if !chart.start_move_plot{
                    if mpx1 != mpx2 && mpy1 != mpy2{
                        let first_p = FCPoint{x:mpx2, y:mpy2 - (mpy2 - mpy1) / 3.0};
                        let second_p = FCPoint{x:mpx2, y:mpy2 - (mpy2 - mpy1) * 2.0 / 3.0};
                        let start_p = FCPoint{x:mpx1,y:mpy1};
                        let mut f_k : f32 = 0.0;
                        let mut f_b : f32 = 0.0;
                        let mut s_k : f32 = 0.0;
                        let mut s_b : f32 = 0.0;
                        line_xy(start_p.x, start_p.y, first_p.x, first_p.y, 0.0, 0.0, &mut f_k, &mut f_b);
                        line_xy(start_p.x, start_p.y, second_p.x, second_p.y, 0.0, 0.0, &mut s_k, &mut s_b);
                        let mut new_yf : f32 = 0.0;
                        let mut new_ys : f32 = 0.0;
                        let mut new_x : f32 = 0.0;
                        if mpx2 > mpx1{
                            new_yf = f_k * (chart.view.size.cx - chart.right_vscale_width) + f_b;
                            new_ys = s_k * (chart.view.size.cx - chart.right_vscale_width) + s_b;
                            new_x = (chart.view.size.cx - chart.right_vscale_width);
                        }
                        else{
                            new_yf = f_b;
                            new_ys = s_b;
                            new_x = chart.left_vscale_width;
                        }
                        chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, start_p.x, start_p.y, new_x, new_yf);
                        if !chart.start_move_plot{
                            chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, start_p.x, start_p.y, new_x, new_ys);
                        }
                    }
                }
            }else if plot.plot_type == "FiboFanline"{
                chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx1, mpy1, mpx2, mpy2);
                if !chart.start_move_plot{
                    if mpx1 != mpx2 && mpy1 != mpy2{
                        let first_p = FCPoint{x:mpx2, y:mpy2 - (mpy2 - mpy1) * 0.382};
                        let second_p = FCPoint{x:mpx2, y:mpy2 - (mpy2 - mpy1) * 0.5};
                        let third_p = FCPoint{x:mpx2, y:mpy2 - (mpy2 - mpy1) * 0.618};
                        let start_p = FCPoint{x:mpx1, y:mpy1};
                        let mut list_p: Vec<FCPoint> = Vec::new();
                        list_p.push(first_p.clone());
						list_p.push(second_p.clone());
						list_p.push(third_p.clone());
						let list_size = list_p.len();
                        for j in 0..list_size{
                            let mut k : f32 = 0.0;
                            let mut b : f32 = 0.0;
                            line_xy(start_p.x, start_p.y, list_p[j as usize].x, list_p[j as usize].y, 0.0, 0.0, &mut k, &mut b);
                            let mut new_x : f32 = 0.0;
                            let mut new_y : f32 = 0.0;
                            if mpx2 > mpx1{
                                new_y = k * (chart.view.size.cx - chart.right_vscale_width) + b;
                                new_x = (chart.view.size.cx - chart.right_vscale_width);
                            }
                            else
                            {
                                new_y = b;
                                new_x = chart.left_vscale_width;
                            }
                            chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, start_p.x, start_p.y, new_x, new_y);
                            if chart.start_move_plot{
                                break;
                            }
                        }
                    }
                }
            }
            else if plot.plot_type == "FiboTimezone"{
                let mut f_value : i32 = 1;
                let aindex = index1;
                let mut pos : i32 = 1;
                let div_height = get_candle_div_height(chart);
                chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, mpx1, 0.0, mpx1, div_height);
                if !chart.start_move_plot{
                    while aindex + f_value <= chart.last_visible_index{
                        f_value = fibonacci_value(pos);
                        let new_index = aindex + f_value;
                        let new_x = get_chart_x(chart, new_index);
                        chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, new_x, 0.0, new_x, div_height);
                        if chart.start_move_plot{
                            break;
                        }
                        pos = pos + 1;
                    }
                }
            }
            else if plot.plot_type == "Percent"{
                let list = get_percent_params(mpy1, mpy2);
                for j in 0..list.len(){
                    chart.start_move_plot = select_segment(FCPoint{x:mp.x, y:mp.y}, chart.left_vscale_width, list[j as usize], chart.view.size.cx - chart.right_vscale_width, list[j as usize]);
                    if chart.start_move_plot{
                        break;
                    }
                }
            }
            if chart.start_move_plot{
				plot.start_key1 = plot.key1;
                plot.start_value1 = plot.value1;
                plot.start_key2 = plot.key2;
                plot.start_value2 = plot.value2;
                plot.start_key3 = plot.key3;
                plot.start_value3 = plot.value3;
                splot = plot.clone();
                break;
            }
        }
        chart.plots[i] = plot.clone();
    }
    return splot.clone();
}

/*
* Draw chart line
* context:Drawing context
* chart:Chart
* clip_rect:Crop area
* div_index:Index of div
* datas:Data
* color:Color
* selected:Is selected or not
*/
pub fn draw_chart_lines(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, chart:&mut FCChart, clip_rect:FCRect, div_index:i32, datas:Vec<f64>, color:String, selected:bool) {
    M_PAINT.lock().unwrap().begin_path(&context);
    let mut last_x : f32 = 0.0;
    let mut last_y : f32 = 0.0;
    let working_area_width = get_chart_workarea_width(chart);
    let max_visible_record = get_max_visible_count(chart, chart.hscale_pixel, working_area_width); 
    for i in chart.first_visible_index..(chart.last_visible_index + 1){
        let x = get_chart_x(chart, i);
        let value = datas[i as usize];
        let y = get_chart_y(chart, div_index, value);
        if i > chart.first_visible_index{
            M_PAINT.lock().unwrap().add_line(&context, last_x, last_y, x, y);
        }
        last_x = x;
        last_y = y;
        if selected {
            let mut kp_interval = max_visible_record / 30;
            if kp_interval < 2 {
                kp_interval = 3;
            }
            if i % kp_interval == 0 {
                M_PAINT.lock().unwrap().fill_rect(&context, color.clone(), x - 3.0, y - 3.0, x + 3.0, y + 3.0);
            }
        }
    }
    M_PAINT.lock().unwrap().draw_path(&context, color, chart.line_width, Vec::new());
	M_PAINT.lock().unwrap().close_path(&context);
}

/*
* Draw chart
* context:Drawing context
* chart:Chart
* clip_rect:Crop area
*/
pub fn draw_chart_stock(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, chart:&mut FCChart, clip_rect:FCRect){
    let data_len = chart.data.len() as i32;
    if data_len > 0 {
		let candle_height = get_candle_div_height(chart);
        let vol_height = get_vol_div_height(chart);
        let ind_height = get_ind_div_height(chart);
        let mut c_width = (((chart.hscale_pixel - 3.0) / 2.0) as i32) as f32;
        let working_area_width = get_chart_workarea_width(chart);
        let max_visible_record = get_max_visible_count(chart, chart.hscale_pixel, working_area_width);
        if c_width < 0.0{
            c_width = 0.0;
        }
        let mut is_trend : bool = false;
        if chart.cycle == "trend"{
            is_trend = true;
        }
        if is_trend{
            M_PAINT.lock().unwrap().begin_path(&context);
            let mut last_x : f32 = 0.0;
            let mut last_y : f32 = 0.0;
            for i in chart.first_visible_index..(chart.last_visible_index + 1){
                let x = get_chart_x(chart, i);
                let close = chart.data[i as usize].close;
                let close_y = get_chart_y(chart, 0, close);
                if i > chart.first_visible_index{
                    M_PAINT.lock().unwrap().add_line(&context, last_x, last_y, x, close_y)
                }
                last_x = x;
                last_y = close_y;
            }
            M_PAINT.lock().unwrap().draw_path(&context, chart.indicator_colors[7].clone(), chart.line_width, Vec::new());
		    M_PAINT.lock().unwrap().close_path(&context);
        }
        let mut has_min_tag : bool = false;
        let mut has_max_tag : bool = false;
        for i in chart.first_visible_index..(chart.last_visible_index + 1){
            let x = get_chart_x(chart, i);
            let iu = i as usize;
            let open = chart.data[iu].open;
            let close = chart.data[iu].close;
            let high = chart.data[iu].high;
            let low = chart.data[iu].low;
            let open_y = get_chart_y(chart, 0, open);
            let close_y = get_chart_y(chart, 0, close);
            let high_y = get_chart_y(chart, 0, high);
            let low_y = get_chart_y(chart, 0, low);
            if close >= open{
                if is_trend{
                }else{
                    M_PAINT.lock().unwrap().draw_line(&context, chart.up_color.clone(), chart.line_width, Vec::new(), x, high_y, x, low_y);
                    if c_width > 0.0{
                        if close == open{
                            M_PAINT.lock().unwrap().draw_line(&context, chart.up_color.clone(), chart.line_width, Vec::new(), x - c_width, close_y, x + c_width, close_y);
                        }
                        else{
                            M_PAINT.lock().unwrap().fill_rect(&context, chart.up_color.clone(), x - c_width, close_y, x + c_width, open_y);
                        }
                    }
                }
            }else{
                if is_trend{
                }else{
                    M_PAINT.lock().unwrap().draw_line(&context, chart.down_color.clone(), chart.line_width, Vec::new(), x, high_y, x, low_y);
                    if c_width > 0.0{
                        M_PAINT.lock().unwrap().fill_rect(&context, chart.down_color.clone(), x - c_width, open_y, x + c_width, close_y);
                    }
                }
            }
            if chart.select_shape == "CANDLE" {
                let mut kp_interval = max_visible_record / 30;
                if kp_interval < 2 {
                    kp_interval = 3;
                }
                if i % kp_interval == 0{
                    if is_trend {
                    } else {
                        M_PAINT.lock().unwrap().fill_rect(&context, chart.indicator_colors[0].clone(), x - 3.0, close_y - 3.0, x + 3.0, close_y + 3.0);
                    }
                }
            } 
            if !is_trend{
                if !has_max_tag{
                    if high == chart.candle_max{
                        let tag = to_fixed(high, chart.candle_digit);
                        let t_size = M_PAINT.lock().unwrap().text_size(&context, tag.clone(), chart.font.clone());
                        M_PAINT.lock().unwrap().draw_text(&context, tag.clone(), chart.text_color.clone(), chart.font.clone(), x - t_size.cx / 2.0, high_y - t_size.cy - 2.0);
                        has_max_tag = true;
                    }
                }
                if !has_min_tag{
                    if low == chart.candle_min{
                        let tag = to_fixed(low, chart.candle_digit);
                        let t_size = M_PAINT.lock().unwrap().text_size(&context, tag.clone(), chart.font.clone());
                        M_PAINT.lock().unwrap().draw_text(&context, tag.clone(), chart.text_color.clone(), chart.font.clone(), x - t_size.cx / 2.0, low_y + 2.0);
                        has_min_tag = true;
                    }
                }
            }
        }
         for i in chart.first_visible_index..(chart.last_visible_index + 1){
            let x = get_chart_x(chart, i);
            let iu = i as usize;
            let open = chart.data[iu].open;
            let close = chart.data[iu].close;
            let open_y = get_chart_y(chart, 0, open);
            let close_y = get_chart_y(chart, 0, close);
            let mut vol_y = 0.0;
            let mut zero_y = 0.0;
            if vol_height > 0.0{
                let volume = chart.data[iu].volume;
                vol_y = get_chart_y(chart, 1, volume);
                zero_y = get_chart_y(chart, 1, 0.0);
            }
            if close >= open{
                if is_trend{
                    if vol_height > 0.0{
                        M_PAINT.lock().unwrap().draw_line(&context, chart.indicator_colors[6].clone(), chart.line_width, Vec::new(), x, vol_y, x, zero_y);
                    }
                }else{
                    if c_width > 0.0{
                        if vol_height > 0.0{
                            M_PAINT.lock().unwrap().fill_rect(&context, chart.up_color.clone(), x - c_width, vol_y, x + c_width, zero_y);
                        }
         
                    }else
                    {
                        if vol_height > 0.0{
                            M_PAINT.lock().unwrap().draw_line(&context, chart.up_color.clone(), chart.line_width, Vec::new(), x - c_width, vol_y, x + c_width, zero_y);
                        }
                    }
                }
            }else{
                if is_trend{
                    if vol_height > 0.0{
                        M_PAINT.lock().unwrap().draw_line(&context, chart.indicator_colors[6].clone(), chart.line_width, Vec::new(), x, vol_y, x, zero_y);
                    }
                }else{
                    if c_width > 0.0{
                        if vol_height > 0.0{
                            M_PAINT.lock().unwrap().fill_rect(&context, chart.down_color.clone(), x - c_width, vol_y, x + c_width, zero_y);
                        }
                    }else{
                        if vol_height > 0.0{
                            M_PAINT.lock().unwrap().draw_line(&context, chart.down_color.clone(), chart.line_width, Vec::new(), x - c_width, vol_y, x + c_width, zero_y);
                        }
                    }
                }
            }
            if chart.select_shape == "VOL" {
                let mut kp_interval = max_visible_record / 30;
                if kp_interval < 2 {
                    kp_interval = 3;
                }
                if i % kp_interval == 0 {
                    M_PAINT.lock().unwrap().fill_rect(&context, chart.indicator_colors[0].clone(), x - 3.0, vol_y - 3.0, x + 3.0, vol_y + 3.0);
                }
            }
        }
        if !is_trend{
			M_PAINT.lock().unwrap().save(&context);
            M_PAINT.lock().unwrap().set_clip(&context, chart.left_vscale_width, 20.0, chart.view.size.cx - chart.right_vscale_width, candle_height);
			if chart.main_indicator == "BOLL" {
				if chart.select_shape == chart.main_indicator && chart.select_shape_ex == "MID"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.boll_mid.clone(), chart.indicator_colors[0].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.boll_mid.clone(), chart.indicator_colors[0].clone(), false);
				}
				if chart.select_shape == chart.main_indicator && chart.select_shape_ex == "UP"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.boll_up.clone(), chart.indicator_colors[1].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.boll_up.clone(), chart.indicator_colors[1].clone(), false);
				}
				if chart.select_shape == chart.main_indicator && chart.select_shape_ex == "DOWM"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.boll_down.clone(), chart.indicator_colors[2].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.boll_down.clone(), chart.indicator_colors[2].clone(), false);
				}
			}else if chart.main_indicator == "MA"{
				if chart.select_shape == chart.main_indicator && chart.select_shape_ex == "5"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.ma5.clone(), chart.indicator_colors[0].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.ma5.clone(), chart.indicator_colors[0].clone(), false);
				}
				if chart.select_shape == chart.main_indicator && chart.select_shape_ex == "10"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.ma10.clone(), chart.indicator_colors[1].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.ma10.clone(), chart.indicator_colors[1].clone(), false);
				}
				if chart.select_shape == chart.main_indicator && chart.select_shape_ex == "20"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.ma20.clone(), chart.indicator_colors[2].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.ma20.clone(), chart.indicator_colors[2].clone(), false);
				}
				if chart.select_shape == chart.main_indicator && chart.select_shape_ex == "30"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.ma30.clone(), chart.indicator_colors[3].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.ma30.clone(), chart.indicator_colors[3].clone(), false);
				}
				if chart.select_shape == chart.main_indicator && chart.select_shape_ex == "120"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.ma120.clone(), chart.indicator_colors[4].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.ma120.clone(), chart.indicator_colors[4].clone(), false);
				}
				if chart.select_shape == chart.main_indicator && chart.select_shape_ex == "250"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.ma250.clone(), chart.indicator_colors[5].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 0, chart.ma250.clone(), chart.indicator_colors[5].clone(), false);
				}
			}
			M_PAINT.lock().unwrap().restore(&context);
        }
        if ind_height > 0.0{
			if chart.show_indicator == "MACD" {
				let zero_y = get_chart_y(chart, 2, 0.0);
				for i in chart.first_visible_index..(chart.last_visible_index + 1){
					let x = get_chart_x(chart, i);
					let iu = i as usize;
					let macd = chart.allmacdarr[iu];
					let macd_y = get_chart_y(chart, 2, macd);
					if macd_y < zero_y {
                        M_PAINT.lock().unwrap().draw_line(&context, chart.indicator_colors[3].clone(), chart.line_width, Vec::new(), x, macd_y, x, zero_y);
                    } else {
                        M_PAINT.lock().unwrap().draw_line(&context, chart.indicator_colors[4].clone(), chart.line_width, Vec::new(), x, macd_y, x, zero_y);
                    }
                    if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "MACD"{
						 let mut kp_interval = max_visible_record / 30;
						if kp_interval < 2 {
							kp_interval = 3;
						}
						if i % kp_interval == 0 {
							M_PAINT.lock().unwrap().fill_rect(&context, chart.indicator_colors[0].clone(), x - 3.0, macd_y - 3.0, x + 3.0, macd_y + 3.0);
						}
                    }
				}
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "DIF"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.alldifarr.clone(), chart.indicator_colors[0].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.alldifarr.clone(), chart.indicator_colors[0].clone(), false);
				}
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "DEA"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.alldeaarr.clone(), chart.indicator_colors[1].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.alldeaarr.clone(), chart.indicator_colors[1].clone(), false);
				}
			} else if chart.show_indicator == "KDJ" {
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "K"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.kdj_k.clone(), chart.indicator_colors[0].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.kdj_k.clone(), chart.indicator_colors[0].clone(), false);
				}
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "D"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.kdj_d.clone(), chart.indicator_colors[1].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.kdj_d.clone(), chart.indicator_colors[1].clone(), false);
				}
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "J"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.kdj_j.clone(), chart.indicator_colors[2].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.kdj_j.clone(), chart.indicator_colors[2].clone(), false);
				}
			} else if chart.show_indicator == "RSI" {
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "6"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.rsi1.clone(), chart.indicator_colors[5].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.rsi1.clone(), chart.indicator_colors[5].clone(), false);
				}
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "12"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.rsi2.clone(), chart.indicator_colors[1].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.rsi2.clone(), chart.indicator_colors[1].clone(), false);
				}
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "24"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.rsi3.clone(), chart.indicator_colors[2].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.rsi3.clone(), chart.indicator_colors[2].clone(), false);
				}
			}
			else if chart.show_indicator == "BIAS" {
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "1"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.bias1.clone(), chart.indicator_colors[5].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.bias1.clone(), chart.indicator_colors[5].clone(), false);
				}
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "2"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.bias2.clone(), chart.indicator_colors[1].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.bias2.clone(), chart.indicator_colors[1].clone(), false);
				}
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "3"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.bias3.clone(), chart.indicator_colors[2].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.bias3.clone(), chart.indicator_colors[2].clone(), false);
				}
			}
			else if chart.show_indicator == "ROC" {
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "ROC"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.roc.clone(), chart.indicator_colors[0].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.roc.clone(), chart.indicator_colors[0].clone(), false);
				}
	        
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "ROCMA"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.roc_ma.clone(), chart.indicator_colors[1].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.roc_ma.clone(), chart.indicator_colors[1].clone(), false);
				}
			} else if chart.show_indicator == "WR" {
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "1"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.wr1.clone(), chart.indicator_colors[0].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.wr1.clone(), chart.indicator_colors[0].clone(), false);
				}
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "2"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.wr2.clone(), chart.indicator_colors[1].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.wr2.clone(), chart.indicator_colors[1].clone(), false);
				}
			} else if chart.show_indicator == "CCI"{
				if chart.select_shape == chart.show_indicator{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.cci.clone(), chart.indicator_colors[0].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.cci.clone(), chart.indicator_colors[0].clone(), false);
				}
			} else if chart.show_indicator == "BBI" {
				if chart.select_shape == chart.show_indicator{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.bbi.clone(), chart.indicator_colors[0].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.bbi.clone(), chart.indicator_colors[0].clone(), false);
				}
			} else if chart.show_indicator == "TRIX" {
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "TRIX"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.trix.clone(), chart.indicator_colors[0].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.trix.clone(), chart.indicator_colors[0].clone(), false);
				}
				
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "TRIXMA"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.trix_ma.clone(), chart.indicator_colors[1].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.trix_ma.clone(), chart.indicator_colors[1].clone(), false);
				}
	        
			} else if chart.show_indicator == "DMA" {
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "DIF"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.dma1.clone(), chart.indicator_colors[0].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.dma1.clone(), chart.indicator_colors[0].clone(), false);
				}
				
				if chart.select_shape == chart.show_indicator && chart.select_shape_ex == "DIFMA"{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.dma2.clone(), chart.indicator_colors[1].clone(), true);
				}else{
					draw_chart_lines(&context, chart, clip_rect.clone(), 2, chart.dma2.clone(), chart.indicator_colors[1].clone(), false);
				}
			}
		}
	}
}

/*
* Draw chart plot
* context:Drawing context
*/
pub fn draw_chart_plot(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, chart:&mut FCChart){
    let plot_point_size : f32 = 5.0;
    let div_height = get_candle_div_height(chart);
    M_PAINT.lock().unwrap().save(&context);
    let candle_height = get_candle_div_height(chart);
    M_PAINT.lock().unwrap().set_clip(&context, chart.left_vscale_width, 20.0, chart.view.size.cx - chart.right_vscale_width, candle_height);
    for i in 0..chart.plots.len(){
		let mut plot = chart.plots[i].clone();
        let mut index1 : i32 = 0;
        let mut index2 : i32 = 0;
        let mut index3 : i32 = 0;
        let mut mpx1 : f32 = 0.0;
        let mut mpy1 : f32 = 0.0;
        let mut mpx2 : f32 = 0.0;
        let mut mpy2 : f32 = 0.0;
        let mut mpx3 : f32 = 0.0;
        let mut mpy3 : f32 = 0.0; 
        let mut rk : f32 = 0.0;
        let mut rb : f32 = 0.0;
        let mut n_high : f64 = 0.0;
        let mut n_low : f64 = 0.0;

       if plot.plot_type == "LRLine" || plot.plot_type == "LRChannel" || plot.plot_type == "LRBand"{
            let mut list: Vec<f64> = Vec::new();
            index1 = get_chart_index_by_date(chart, plot.key1);
            index2 = get_chart_index_by_date(chart, plot.key2);
            let min_index = index1.min(index2);
            let max_index = index1.max(index2);
            for j in min_index..(max_index + 1){
                list.push(chart.data[j as usize].close);
            }
            linear_regression_equation(list, &mut rk, &mut rb);
            plot.value1 = rb as f64;
            plot.value2 = (rk * ((max_index - min_index + 1) as f32) + rb) as f64;
        }
        else if plot.plot_type == "BoxLine" || plot.plot_type == "TironeLevels"{
            get_candle_range(chart, &mut plot, &mut n_high, &mut n_low);
            index1 = get_chart_index_by_date(chart, plot.key1);
            index2 = get_chart_index_by_date(chart, plot.key2);
            plot.key1 = get_chart_date_by_index(chart, index1.min(index2));
            plot.key2 = get_chart_date_by_index(chart, index1.max(index2));
            plot.value1 = n_high;
            plot.value2 = n_low;
        } 
        if plot.key1 > 0.0{
            index1 = get_chart_index_by_date(chart, plot.key1);
            mpx1 = get_chart_x(chart, index1);
            mpy1 = get_chart_y(chart, 0, plot.value1);
            if chart.splot.vid == plot.vid
            {
                M_PAINT.lock().unwrap().fill_ellipse(&context, plot.point_color.clone(), mpx1 - plot_point_size, mpy1 - plot_point_size, mpx1 + plot_point_size, mpy1 + plot_point_size);
            }
        }
        if plot.key2 > 0.0{
            index2 = get_chart_index_by_date(chart, plot.key2);
            mpx2 = get_chart_x(chart, index2);
            mpy2 = get_chart_y(chart, 0, plot.value2);
            if chart.splot.vid == plot.vid
            {
                M_PAINT.lock().unwrap().fill_ellipse(&context, plot.point_color.clone(), mpx2 - plot_point_size, mpy2 - plot_point_size, mpx2 + plot_point_size, mpy2 + plot_point_size);
            }
        }
        if plot.key3 > 0.0{
            index3 = get_chart_index_by_date(chart, plot.key3);
            mpx3 = get_chart_x(chart, index3);
            mpy3 = get_chart_y(chart, 0, plot.value3);
            if chart.splot.vid == plot.vid
            {
                M_PAINT.lock().unwrap().fill_ellipse(&context, plot.point_color.clone(), mpx3 - plot_point_size, mpy3 - plot_point_size, mpx3 + plot_point_size, mpy3 + plot_point_size);
            }
        }
        if plot.plot_type == "Line"{
            let mut k : f32 = 0.0;
            let mut b : f32 = 0.0;
            line_xy(mpx1, mpy1, mpx2, mpy2, 0.0, 0.0, &mut k, &mut b);
            if mpx2 == mpx1{
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, 0.0, mpx1, div_height);
            }else{
                let new_x1 = chart.left_vscale_width;
                let new_y1 = new_x1 * k + b;
                let new_x2 = chart.view.size.cx - chart.right_vscale_width;
                let new_y2 = new_x2 * k + b;
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), new_x1, new_y1, new_x2, new_y2);
            }
        }
        else if plot.plot_type == "AngleLine"{
            let mut k : f32 = 0.0;
            let mut b : f32 = 0.0;
            line_xy(mpx1, mpy1, mpx2, mpy2, 0.0, 0.0, &mut k, &mut b);
            if mpx2 == mpx1{
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, 0.0, mpx1, div_height);
            }else{
                let new_x1 = chart.left_vscale_width;
                let new_y1 = new_x1 * k + b;
                let new_x2 = chart.view.size.cx - chart.right_vscale_width;
                let new_y2 = new_x2 * k + b;
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), new_x1, new_y1, new_x2, new_y2);
            }
            line_xy(mpx1, mpy1, mpx3, mpy3, 0.0, 0.0, &mut k, &mut b);
            if mpx3 == mpx1{
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, 0.0, mpx1, div_height);
            }else{
                let new_x1 = chart.left_vscale_width;
                let new_y1 = new_x1 * k + b;
                let new_x2 = chart.view.size.cx - chart.right_vscale_width;
                let new_y2 = new_x2 * k + b;
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), new_x1, new_y1, new_x2, new_y2);
            }
        }
         else if plot.plot_type == "Parallel"{
            let mut k : f32 = 0.0;
            let mut b : f32 = 0.0;
            line_xy(mpx1, mpy1, mpx2, mpy2, 0.0, 0.0, &mut k, &mut b);
            if mpx2 == mpx1{
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, 0.0, mpx1, div_height);
            }else{
                let new_x1 = chart.left_vscale_width;
                let new_y1 = new_x1 * k + b;
                let new_x2 = chart.view.size.cx - chart.right_vscale_width;
                let new_y2 = new_x2 * k + b;
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), new_x1, new_y1, new_x2, new_y2);
            }
            let new_b = mpy3 - k * mpx3;
            if mpx2 == mpx1{
               M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx3, 0.0, mpx3, div_height);
            }else{
                let new_x1 = chart.left_vscale_width;
                let new_y1 = new_x1 * k + new_b;
                let new_x2 = chart.view.size.cx - chart.right_vscale_width;
                let new_y2 = new_x2 * k + new_b;
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), new_x1, new_y1, new_x2, new_y2);
            }
        }
        else if plot.plot_type == "Percent"{
            let list = get_percent_params(mpy1, mpy2);
            let mut texts: Vec<String> = Vec::new();
            texts.push("0%".to_string());
            texts.push("25%".to_string());
            texts.push("50%".to_string());
            texts.push("75%".to_string());
            texts.push("100%".to_string());
            for j in 0..list.len(){
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), chart.left_vscale_width, list[j as usize], chart.view.size.cx - chart.right_vscale_width, list[j as usize]);
                let t_size = M_PAINT.lock().unwrap().text_size(&context, texts[j as usize].clone(), chart.font.clone());
                M_PAINT.lock().unwrap().draw_text(&context, texts[j as usize].clone(), chart.text_color.clone(), chart.font.clone(), chart.left_vscale_width + 5.0, list[j as usize] - t_size.cy - 2.0);
            }
        }
        else if plot.plot_type == "FiboTimezone"{
            let mut f_value : i32 = 1;
            let aindex = index1;
            let mut pos : i32 = 1;
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, 0.0, mpx1, div_height);
            let t_size = M_PAINT.lock().unwrap().text_size(&context, "1".to_string(), chart.font.clone());
            M_PAINT.lock().unwrap().draw_text(&context, "1".to_string(), chart.text_color.clone(), chart.font.clone(), mpx1, div_height - t_size.cy);
            while aindex + f_value <= chart.last_visible_index{
                f_value = fibonacci_value(pos);
                let new_index = aindex + f_value;
                let new_x = get_chart_x(chart, new_index);
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), new_x, 0.0, new_x, div_height);
                let t_size = M_PAINT.lock().unwrap().text_size(&context, f_value.to_string(), chart.font.clone());
                M_PAINT.lock().unwrap().draw_text(&context, f_value.to_string(), chart.text_color.clone(), chart.font.clone(), new_x, div_height - t_size.cy);
                pos = pos + 1;
            }
        }
        else if plot.plot_type == "SpeedResist"{
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, mpx2, mpy2);
            if mpx1 != mpx2 && mpy1 != mpy2{
                let first_p = FCPoint{x:mpx2, y:mpy2 - (mpy2 - mpy1) / 3.0};
                let second_p = FCPoint{x:mpx2, y:mpy2 - (mpy2 - mpy1) * 2.0 / 3.0};
                let start_p = FCPoint{x:mpx1,y:mpy1};
                let mut f_k : f32 = 0.0;
                let mut f_b : f32 = 0.0;
                let mut s_k : f32 = 0.0;
                let mut s_b : f32 = 0.0;
                line_xy(start_p.x, start_p.y, first_p.x, first_p.y, 0.0, 0.0, &mut f_k, &mut f_b);
                line_xy(start_p.x, start_p.y, second_p.x, second_p.y, 0.0, 0.0, &mut s_k, &mut s_b);
                let new_yf : f32 = 0.0;
                let new_ys : f32 = 0.0;
                let new_x : f32 = 0.0;
                let mut new_yf : f32 = 0.0;
                let mut new_ys : f32 = 0.0;
                let mut new_x : f32 = 0.0;
                if mpx2 > mpx1{
                    new_yf = f_k * (chart.view.size.cx - chart.right_vscale_width) + f_b;
                    new_ys = s_k * (chart.view.size.cx - chart.right_vscale_width) + s_b;
                    new_x = (chart.view.size.cx - chart.right_vscale_width);
                }
                else{
                    new_yf = f_b;
                    new_ys = s_b;
                    new_x = chart.left_vscale_width;
                }
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), start_p.x, start_p.y, new_x, new_yf);
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), start_p.x, start_p.y, new_x, new_ys);
            }
        }
        else if plot.plot_type == "LRLine"{
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, mpx2, mpy2);
        }
        else if plot.plot_type == "LRBand"{
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, mpx2, mpy2);
            let mut up_sub_value : f64 = 0.0;
            let mut down_sub_value : f64 = 0.0;
            get_lrband_range(chart, &mut plot, rk, rb, &mut up_sub_value, &mut down_sub_value);
            
            mpy1 = get_chart_y(chart, 0, plot.value1 + up_sub_value);
            mpy2 = get_chart_y(chart, 0, plot.value2 + up_sub_value);
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, mpx2, mpy2);
            
            mpy1 = get_chart_y(chart, 0, plot.value1 - down_sub_value);
            mpy2 = get_chart_y(chart, 0, plot.value2 - down_sub_value);
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, mpx2, mpy2);
        }
        else if plot.plot_type == "LRChannel"{
			let mut up_sub_value : f64 = 0.0;
            let mut down_sub_value : f64 = 0.0;
            get_lrband_range(chart, &mut plot, rk, rb, &mut up_sub_value, &mut down_sub_value);
            let mut k : f32 = 0.0;
            let mut b : f32 = 0.0;
            line_xy(mpx1, mpy1, mpx2, mpy2, 0.0, 0.0, &mut k, &mut b);
            let right_x = chart.view.size.cx - chart.right_vscale_width;
            let mut right_y = right_x * k + b;
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, right_x, right_y);
            mpy1 = get_chart_y(chart, 0, plot.value1 + up_sub_value);
            mpy2 = get_chart_y(chart, 0, plot.value2 + up_sub_value);
            line_xy(mpx1, mpy1, mpx2, mpy2, 0.0, 0.0, &mut k, &mut b);
            right_y = right_x * k + b;
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, right_x, right_y);
            mpy1 = get_chart_y(chart, 0, plot.value1 - down_sub_value);
            mpy2 = get_chart_y(chart, 0, plot.value2 - down_sub_value);
            line_xy(mpx1, mpy1, mpx2, mpy2, 0.0, 0.0, &mut k, &mut b);
            right_y = right_x * k + b;
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, right_x, right_y);
        }
        else if plot.plot_type == "FiboFanline"{
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, mpx2, mpy2);
            if mpx1 != mpx2 && mpy1 != mpy2{
                let first_p = FCPoint{x:mpx2, y:mpy2 - (mpy2 - mpy1) * 0.382};
                let second_p = FCPoint{x:mpx2, y:mpy2 - (mpy2 - mpy1) * 0.5};
                let third_p = FCPoint{x:mpx2, y:mpy2 - (mpy2 - mpy1) * 0.618};
                let start_p = FCPoint{x:mpx1, y:mpy1};
                let mut list_p: Vec<FCPoint> = Vec::new();
                list_p.push(first_p.clone());
				list_p.push(second_p.clone());
				list_p.push(third_p.clone());
				let list_size = list_p.len();
                for j in 0..list_size{
                    let mut k : f32 = 0.0;
                    let mut b : f32 = 0.0;
                    line_xy(start_p.x, start_p.y, list_p[j as usize].x, list_p[j as usize].y, 0.0, 0.0, &mut k, &mut b);
                    let mut new_x : f32 = 0.0;
                    let mut new_y : f32 = 0.0;
                    if mpx2 > mpx1{
                        new_y = k * (chart.view.size.cx - chart.right_vscale_width) + b;
                        new_x = (chart.view.size.cx - chart.right_vscale_width);
                    }
                    else
                    {
                        new_y = b;
                        new_x = chart.left_vscale_width;
                    }
                    M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), start_p.x, start_p.y, new_x, new_y);
                }
            }
        }
        else if plot.plot_type == "Segment"{
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, mpx2, mpy2);
        }else if plot.plot_type == "Ray"{
            let mut k : f32 = 0.0;
            let mut b : f32 = 0.0;
            line_xy(mpx1, mpy1, mpx2, mpy2, 0.0, 0.0, &mut k, &mut b);
            if k != 0.0 || b != 0.0 {
                let left_x = chart.left_vscale_width;
                let left_y = left_x * k + b;
                let right_x = chart.view.size.cx - chart.right_vscale_width;
                let right_y = right_x * k + b;
                if mpx1 >= mpx2 {
                    M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), left_x, left_y, mpx1, mpy1);
                } else {
                    M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, right_x, right_y);
                }
            }
            else {
                if mpy1 >= mpy2 {
                    M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, mpx1, 0.0);
                } else {
                    M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, mpx1, div_height);
                }
            }
        }else if plot.plot_type == "Triangle"{
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, mpx2, mpy2);
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx2, mpy2, mpx3, mpy3);
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, mpx3, mpy3);
        }else if plot.plot_type == "Rect"{
            let s_x1 : f32 = mpx1.min(mpx2);
            let s_y1 : f32 = mpy1.min(mpy2);
            let s_x2 : f32 = mpx1.max(mpx2);
            let s_y2 : f32 = mpy1.max(mpy2);
            M_PAINT.lock().unwrap().draw_rect(&context, plot.line_color.clone(), plot.line_width, Vec::new(), s_x1, s_y1, s_x2, s_y2);
        }else if plot.plot_type == "Cycle"{
            let r = ((mpx2 - mpx1) * (mpx2 - mpx1) + (mpy2 - mpy1) * (mpy2 - mpy1)).abs().sqrt();
            M_PAINT.lock().unwrap().draw_ellipse(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1 - r, mpy1 - r, mpx1 + r, mpy1 + r);
        }else if plot.plot_type == "CircumCycle"{
            let mut o_x : f32 = 0.0;
            let mut o_y : f32 = 0.0;
            let mut r : f32 = 0.0;
            ellipse_or(mpx1, mpy1, mpx2, mpy2, mpx3, mpy3, &mut o_x, &mut o_y, &mut r);
            M_PAINT.lock().unwrap().draw_ellipse(&context, plot.line_color.clone(), plot.line_width, Vec::new(), o_x - r, o_y - r, o_x + r, o_y + r);
        }else if plot.plot_type == "Ellipse"{
           let mut x1 : f32 = 0.0;
            let mut y1 : f32 = 0.0;
            let mut x2 : f32 = 0.0;
            let mut y2 : f32 = 0.0;
            if mpx1 <= mpx2{
                x1 = mpx2;
                y1 = mpy2;
                x2 = mpx1;
                y2 = mpy1;
            }else{
                x1 = mpx1;
                y1 = mpy1;
                x2 = mpx2;
                y2 = mpy2;
            }
            let x = x1 - (x1 - x2);
            let mut y : f32 = 0.0;
            let width = (x1 - x2) * 2.0;
            let mut height : f32 = 0.0;
            if y1 >= y2{
                height = (y1 - y2) * 2.0;
            }
            else{
                height = (y2 - y1) * 2.0;
            }
            y = y2 - height / 2.0;
            M_PAINT.lock().unwrap().draw_ellipse(&context, plot.line_color.clone(), plot.line_width, Vec::new(), x, y, x + width, y + height);
        }else if plot.plot_type == "ParalleGram"{
            let mut x4 : f32 = 0.0;
            let mut y4 : f32 = 0.0;
            parallelogram(mpx1, mpy1, mpx2, mpy2, mpx3, mpy3, &mut x4, &mut y4);
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx1, mpy1, mpx2, mpy2);
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx2, mpy2, mpx3, mpy3);
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), mpx3, mpy3, x4, y4);
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), x4, y4, mpx1, mpy1);
        }else if plot.plot_type == "BoxLine"{
            let s_x1 : f32 = mpx1.min(mpx2);
            let s_y1 : f32 = mpy1.min(mpy2);
            let s_x2 : f32 = mpx1.max(mpx2);
            let s_y2 : f32 = mpy1.max(mpy2);
            M_PAINT.lock().unwrap().draw_rect(&context, plot.line_color.clone(), plot.line_width, Vec::new(), s_x1, s_y1, s_x2, s_y2);
            let str = "COUNT:".to_string() + &(((index2 - index1).abs() as i32) + 1).to_string();
            let b_size = M_PAINT.lock().unwrap().text_size(&context, str.clone(), chart.font.clone());
            M_PAINT.lock().unwrap().draw_text(&context, str, chart.text_color.clone(), chart.font.clone(), s_x1 + 2.0, s_y1 + 2.0);
            let mut close_list: Vec<f64> = Vec::new();
            for j in index1..(index2 + 1){
                close_list.push(chart.data[j as usize].close);
            }
            let avg_close = avg_value(close_list);
            let close_y = get_chart_y(chart, 0, avg_close);
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), s_x1, close_y, s_x2, close_y);
            let draw_avg = "AVG:".to_string() + &to_fixed(avg_close, chart.candle_digit);
            let t_size = M_PAINT.lock().unwrap().text_size(&context, draw_avg.clone(), chart.font.clone());
            M_PAINT.lock().unwrap().draw_text(&context, draw_avg.clone(), chart.text_color.clone(), chart.font.clone(), s_x1 + 2.0, close_y - t_size.cy - 2.0);
        }
        else if plot.plot_type == "TironeLevels"{
            let s_x1 : f32 = mpx1.min(mpx2);
            let s_y1 : f32 = mpy1.min(mpy2);
            let s_x2 : f32 = mpx1.max(mpx2);
            let s_y2 : f32 = mpy1.max(mpy2);
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), s_x1, s_y1, s_x2, s_y1);
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), s_x1, s_y2, s_x2, s_y2);
            M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), s_x1 + (s_x2 - s_x1) / 2.0, s_y1, s_x1 + (s_x2 - s_x1) / 2.0, s_y2);
            let t1 = n_high;
            let t2 = n_high - (n_high - n_low) / 3.0;
            let t3 = n_high - (n_high - n_low) / 2.0;
            let t4 = n_high - 2.0 * (n_high - n_low) / 3.0;
            let t5 = n_low;
            let mut tlist: Vec<f64> = Vec::new();
            tlist.push(t2);
            tlist.push(t3);
            tlist.push(t4);
            for j in 0..tlist.len(){
                let y = get_chart_y(chart, 0, tlist[j as usize]);
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), chart.left_vscale_width, y, chart.view.size.cx - chart.right_vscale_width, y);
                let str = to_fixed(tlist[j], chart.candle_digit);
                let t_size = M_PAINT.lock().unwrap().text_size(&context, str.clone(), chart.font.clone());
                M_PAINT.lock().unwrap().draw_text(&context, str.clone(), chart.text_color.clone(), chart.font.clone(), chart.left_vscale_width + 2.0, y - t_size.cy - 2.0);
            }
        }
        else if plot.plot_type == "GoldenRatio"{
            let s_x1 : f32 = mpx1.min(mpx2);
            let s_y1 : f32 = mpy1.min(mpy2);
            let s_x2 : f32 = mpx1.max(mpx2);
            let s_y2 : f32 = mpy1.max(mpy2);
            let mut ranges: Vec<f32> = Vec::new();
            ranges.push(0.0);
            ranges.push(0.236);
            ranges.push(0.382);
            ranges.push(0.5);
            ranges.push(0.618);
            ranges.push(0.809);
            ranges.push(1.0);
            ranges.push(1.382);
            ranges.push(1.618);
            ranges.push(2.0);
            ranges.push(2.382);
            ranges.push(2.618);
            let min_value = plot.value1.min(plot.value2);
            let max_value = plot.value1.max(plot.value2);
            for j in 0..ranges.len(){
                let mut new_y : f32 = 0.0;
                if s_y1 <= s_y2{
                    new_y = s_y1 + (s_y2 - s_y1) * ranges[j as usize];
                }else{
                    new_y =  s_y2 + (s_y1 - s_y2) * (1.0 - ranges[j as usize]);
                }
                M_PAINT.lock().unwrap().draw_line(&context, plot.line_color.clone(), plot.line_width, Vec::new(), chart.left_vscale_width, new_y, chart.view.size.cx - chart.right_vscale_width, new_y);
                let value = get_candle_div_value(chart, FCPoint{x:0.0, y:new_y});
                let str = to_fixed(value, chart.candle_digit);
                let t_size = M_PAINT.lock().unwrap().text_size(&context, str.clone(), chart.font.clone());
                M_PAINT.lock().unwrap().draw_text(&context, str.clone(), chart.text_color.clone(), chart.font.clone(), chart.left_vscale_width + 2.0, new_y - t_size.cy - 2.0);
            }
        }
        chart.plots[i] = plot.clone();
    }
    M_PAINT.lock().unwrap().restore(&context);
}

/*
* Draw chart scale
* context:Drawing context
* chart:Chart
* clip_rect:Crop area
*/
pub fn draw_chart_scale(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, chart:&mut FCChart, clip_rect:FCRect){
    if chart.left_vscale_width > 0.0{
        M_PAINT.lock().unwrap().draw_line(&context, chart.scale_color.clone(), chart.line_width, Vec::new(), chart.left_vscale_width, 0.0, chart.left_vscale_width, chart.view.size.cy - chart.hscale_height);
    }
    if chart.right_vscale_width > 0.0{
        M_PAINT.lock().unwrap().draw_line(&context, chart.scale_color.clone(), chart.line_width, Vec::new(), chart.view.size.cx - chart.right_vscale_width, 0.0, chart.view.size.cx - chart.right_vscale_width, chart.view.size.cy - chart.hscale_height);
    }
    if chart.hscale_height > 0.0{
        M_PAINT.lock().unwrap().draw_line(&context, chart.scale_color.clone(), chart.line_width, Vec::new(), 0.0, chart.view.size.cy - chart.hscale_height, chart.view.size.cx, chart.view.size.cy - chart.hscale_height);
    }
    let candle_div_height = get_candle_div_height(chart);
    let vol_div_height = get_vol_div_height(chart);
    let ind_div_height = get_ind_div_height(chart);
    let ind_div_height2 = get_ind_div_height2(chart);
    if vol_div_height > 0.0{
        M_PAINT.lock().unwrap().draw_line(&context, chart.scale_color.clone(), chart.line_width, Vec::new(), chart.left_vscale_width, candle_div_height, chart.view.size.cx - chart.right_vscale_width, candle_div_height);
    }
    if ind_div_height > 0.0{
        M_PAINT.lock().unwrap().draw_line(&context, chart.scale_color.clone(), chart.line_width, Vec::new(), chart.left_vscale_width, candle_div_height + vol_div_height, chart.view.size.cx - chart.right_vscale_width, candle_div_height + vol_div_height);
    }
    if ind_div_height2 > 0.0{
        M_PAINT.lock().unwrap().draw_line(&context, chart.scale_color.clone(), chart.line_width, Vec::new(), chart.left_vscale_width, candle_div_height + vol_div_height + ind_div_height, chart.view.size.cx - chart.right_vscale_width, candle_div_height + vol_div_height + ind_div_height);
    }
    let data_len = chart.data.len() as i32;
    if data_len > 0 {
		let mut grid_step : f64 = 0.0;
		let mut grid_digit : i32 = 0;
		chart_grid_scale(chart.candle_min, chart.candle_max,  (candle_div_height - chart.candle_padding_top - chart.candle_padding_bottom) / 2.0, chart.vscale_distance, chart.vscale_distance / 2.0, ((candle_div_height - chart.candle_padding_top - chart.candle_padding_bottom) / chart.vscale_distance) as i32, &mut grid_step, &mut grid_digit);
		if grid_step > 0.0{
			let mut draw_values: Vec<f64> = Vec::new();
			let mut is_trend : bool = false;
			if chart.cycle == "trend"{
				is_trend = true;
			}
			let mut first_open : f64 = 0.0;
			if is_trend{
				first_open = chart.data[chart.first_visible_index as usize].close;
				let mut sub_value = (chart.candle_max - chart.candle_min);
				let count = ((candle_div_height - chart.candle_padding_top - chart.candle_padding_bottom) / chart.vscale_distance) as i32;
				if count > 0{
					sub_value = sub_value / (count as f64);
				}
				let mut start = first_open;
				while start < chart.candle_max{
					start = start + sub_value;
					if start <= chart.candle_max{
						draw_values.push(start);
					}
				}
				start = first_open;
				while start > chart.candle_min{
					start -= sub_value;
					if start >= chart.candle_min{
						draw_values.push(start);
					}
				}
			}else{
				let mut start : f64 = 0.0;
				if chart.candle_min >= 0.0 {
					while start + grid_step < chart.candle_min {
						start = start + grid_step;
					}
				} else {
					while start - grid_step > chart.candle_min {
						start = start - grid_step;
					}
				}

				while start <= chart.candle_max {
					if start > chart.candle_min{
						draw_values.push(start);
					}
					start = start + grid_step;
				}
			}
			draw_values.push(first_open);
			for i in 0..draw_values.len(){
				let start = draw_values[i as usize];
				let haxis_y = get_chart_y(chart, 0, start);
				if haxis_y < 1.0 || haxis_y > candle_div_height {
						continue;
				}
				M_PAINT.lock().unwrap().draw_line(&context, chart.grid_color.clone(), chart.line_width, Vec::new(), chart.left_vscale_width, haxis_y, chart.view.size.cx - chart.right_vscale_width, haxis_y);
				M_PAINT.lock().unwrap().draw_line(&context, chart.scale_color.clone(), chart.line_width, Vec::new(), chart.left_vscale_width - 8.0, haxis_y, chart.left_vscale_width, haxis_y);
				M_PAINT.lock().unwrap().draw_line(&context, chart.scale_color.clone(), chart.line_width, Vec::new(), chart.view.size.cx - chart.right_vscale_width, haxis_y, chart.view.size.cx - chart.right_vscale_width + 8.0, haxis_y);
				let t_size =  M_PAINT.lock().unwrap().text_size(&context, to_fixed(start, chart.candle_digit), chart.font.clone());
				if is_trend{
					let diff_range = ((start - first_open) / first_open * 100.0);
					let diff_range_str = to_fixed(diff_range, chart.candle_digit);
					if diff_range >= 0.0{
						M_PAINT.lock().unwrap().draw_text(&context, diff_range_str.clone(), chart.up_color.clone(), chart.font.clone(), chart.view.size.cx - chart.right_vscale_width + 10.0, haxis_y as f32 - t_size.cy / 2.0);
					}else{
						M_PAINT.lock().unwrap().draw_text(&context, diff_range_str.clone(), chart.down_color.clone(), chart.font.clone(), chart.view.size.cx - chart.right_vscale_width + 10.0, haxis_y as f32 - t_size.cy / 2.0);
					}
				}else{
					M_PAINT.lock().unwrap().draw_text(&context, to_fixed(start, chart.candle_digit), chart.text_color.clone(), chart.font.clone(), chart.view.size.cx - chart.right_vscale_width + 10.0, haxis_y as f32 - t_size.cy / 2.0);
				}
				M_PAINT.lock().unwrap().draw_text(&context, to_fixed(start, chart.candle_digit), chart.text_color.clone(), chart.font.clone(), chart.left_vscale_width - t_size.cx - 10.0, haxis_y as f32 - t_size.cy / 2.0);
			}
		}
		chart_grid_scale(chart.vol_min, chart.vol_max, (vol_div_height - chart.vol_padding_top - chart.vol_padding_bottom) / 2.0, chart.vscale_distance, chart.vscale_distance / 2.0, ((vol_div_height - chart.vol_padding_top - chart.vol_padding_bottom) / chart.vscale_distance) as i32, &mut grid_step, &mut grid_digit);
		if grid_step > 0.0{
			let mut start : f64 = 0.0;
			if chart.vol_min >= 0.0 {
				while start + grid_step < chart.vol_min {
					start = start + grid_step;
				}
			} else {
				while start - grid_step > chart.vol_min {
					start = start - grid_step;
				}
			}
			while start <= chart.vol_max {
				if start > chart.vol_min{
					let haxis_y = get_chart_y(chart, 1, start);
					if haxis_y < candle_div_height || haxis_y > candle_div_height + vol_div_height {
						continue;
					}
					M_PAINT.lock().unwrap().draw_line(&context, chart.grid_color.clone(), chart.line_width, Vec::new(), chart.left_vscale_width, haxis_y, chart.view.size.cx - chart.right_vscale_width, haxis_y);
					M_PAINT.lock().unwrap().draw_line(&context, chart.scale_color.clone(), chart.line_width, Vec::new(), chart.left_vscale_width - 8.0, haxis_y, chart.left_vscale_width, haxis_y);
					M_PAINT.lock().unwrap().draw_line(&context, chart.scale_color.clone(), chart.line_width, Vec::new(), chart.view.size.cx - chart.right_vscale_width, haxis_y, chart.view.size.cx - chart.right_vscale_width + 8.0, haxis_y);
					let t_size = M_PAINT.lock().unwrap().text_size(&context, to_fixed(start, chart.vol_digit), chart.font.clone());
					M_PAINT.lock().unwrap().draw_text(&context, to_fixed(start, chart.vol_digit), chart.text_color.clone(), chart.font.clone(), chart.view.size.cx - chart.right_vscale_width + 10.0, haxis_y as f32 - t_size.cy / 2.0);
					M_PAINT.lock().unwrap().draw_text(&context, to_fixed(start, chart.vol_digit), chart.text_color.clone(), chart.font.clone(), chart.left_vscale_width - t_size.cx - 10.0, haxis_y as f32 - t_size.cy / 2.0);
				}
				start = start + grid_step;
			}
		}
		if ind_div_height > 0.0{
			chart_grid_scale(chart.ind_min, chart.ind_max, (ind_div_height - chart.ind_padding_top - chart.ind_padding_bottom) / 2.0, chart.vscale_distance, chart.vscale_distance / 2.0, ((ind_div_height - chart.ind_padding_top - chart.ind_padding_bottom) / chart.vscale_distance) as i32, &mut grid_step, &mut grid_digit);
			if grid_step > 0.0{
				let mut start : f64 = 0.0;
				if chart.ind_min >= 0.0 {
					while start + grid_step < chart.ind_min {
						start = start + grid_step;
					}
				} else {
					while start - grid_step > chart.ind_min {
						start = start - grid_step;
					}
				}
				while start <= chart.ind_max {
					if start > chart.ind_min{
						let haxis_y = get_chart_y(chart, 2, start);
						if haxis_y < candle_div_height + vol_div_height || haxis_y > candle_div_height + vol_div_height + ind_div_height {
							continue;
						}
						M_PAINT.lock().unwrap().draw_line(&context, chart.grid_color.clone(), chart.line_width, Vec::new(), chart.left_vscale_width, haxis_y, chart.view.size.cx - chart.right_vscale_width, haxis_y);
						M_PAINT.lock().unwrap().draw_line(&context, chart.scale_color.clone(), chart.line_width, Vec::new(), chart.left_vscale_width - 8.0, haxis_y, chart.left_vscale_width, haxis_y);
						M_PAINT.lock().unwrap().draw_line(&context, chart.scale_color.clone(), chart.line_width, Vec::new(), chart.view.size.cx - chart.right_vscale_width, haxis_y, chart.view.size.cx - chart.right_vscale_width + 8.0, haxis_y);
						let t_size = M_PAINT.lock().unwrap().text_size(&context, to_fixed(start, chart.ind_digit), chart.font.clone());
						M_PAINT.lock().unwrap().draw_text(&context, to_fixed(start, chart.ind_digit), chart.text_color.clone(), chart.font.clone(), chart.view.size.cx - chart.right_vscale_width + 10.0, haxis_y as f32 - t_size.cy / 2.0);
						M_PAINT.lock().unwrap().draw_text(&context, to_fixed(start, chart.ind_digit), chart.text_color.clone(), chart.font.clone(), chart.left_vscale_width - t_size.cx - 10.0, haxis_y as f32 - t_size.cy / 2.0);
					}
					start = start + grid_step;
				}
			}  
		}
		if chart.hscale_height > 0.0{
			let mut d_left = chart.left_vscale_width + 10.0;
			for i in chart.first_visible_index..(chart.last_visible_index + 1){
				let x_text = chart.data[i as usize].date.to_string();
				let t_size = M_PAINT.lock().unwrap().text_size(&context, x_text.clone(), chart.font.clone());
				let x = get_chart_x(chart, i);
				let dx = x - t_size.cx / 2.0;
				if dx > d_left && dx < chart.view.size.cx - chart.right_vscale_width - 10.0{
					M_PAINT.lock().unwrap().draw_line(&context, chart.scale_color.clone(), chart.line_width, Vec::new(), x, chart.view.size.cy - chart.hscale_height, x, chart.view.size.cy - chart.hscale_height + 8.0);
					M_PAINT.lock().unwrap().draw_text(&context, x_text.clone(), chart.text_color.clone(), chart.font.clone(), dx, chart.view.size.cy - chart.hscale_height + 8.0 - t_size.cy / 2.0 + 7.0);
					d_left = x + t_size.cx;
				}
			}
		}
    }
}

/*
* Draw chart cross line
* context:Drawing context
* chart:Chart
* clip_rect:Crop area
*/
pub fn draw_chart_cross_line(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, chart:&mut FCChart, clip_rect:FCRect){
	let data_len = chart.data.len() as i32;
    if data_len > 0 {
		let candle_div_height = get_candle_div_height(chart);
		let vol_div_height = get_vol_div_height(chart);
		let ind_div_height = get_ind_div_height(chart);
		let mut cross_line_index = chart.cross_stop_index;
		if cross_line_index == -1 || !chart.show_cross_line {
			cross_line_index = chart.last_visible_index;
		}
		if vol_div_height > 0.0{
			let voltxt = "VOL ".to_string() + &to_fixed(chart.data[cross_line_index as usize].volume, chart.vol_digit);
			let vol_size = M_PAINT.lock().unwrap().text_size(&context, voltxt.clone(), chart.font.clone());
			M_PAINT.lock().unwrap().draw_text(&context, voltxt.clone(), chart.text_color.clone(), chart.font.clone(), chart.left_vscale_width + 5.0, candle_div_height + 5.0);
		}
		let is_trend : bool = false;
		if !is_trend{
			let mut draw_titles = Vec::new();
			let mut draw_colors = Vec::new();
			if chart.main_indicator == "MA" {
                if chart.ma5.len() > 0{
				    draw_titles.push("MA5 ".to_string() + &to_fixed(chart.ma5[cross_line_index as usize], chart.candle_digit));
                }else{
                    draw_titles.push("MA5".to_string());
                }
                 if chart.ma10.len() > 0{
				    draw_titles.push("MA10 ".to_string() + &to_fixed(chart.ma10[cross_line_index as usize], chart.candle_digit));
                 }else{
                     draw_titles.push("MA10".to_string());
                 }
                 if chart.ma20.len() > 0{
				    draw_titles.push("MA20 ".to_string() + &to_fixed(chart.ma20[cross_line_index as usize], chart.candle_digit));
                 }else{
                     draw_titles.push("MA20".to_string());
                 }
                 if chart.ma30.len() > 0{
				    draw_titles.push("MA30 ".to_string() + &to_fixed(chart.ma30[cross_line_index as usize], chart.candle_digit));
                 }else{
                     draw_titles.push("MA30".to_string());
                 }
                 if chart.ma120.len() > 0{
				    draw_titles.push("MA120 ".to_string() + &to_fixed(chart.ma120[cross_line_index as usize], chart.candle_digit));
                 }else{
                     draw_titles.push("MA120".to_string());
                 }
                 if chart.ma250.len() > 0 {
				    draw_titles.push("MA250 ".to_string() + &to_fixed(chart.ma250[cross_line_index as usize], chart.candle_digit));
                 }else{
                     draw_titles.push("MA250".to_string());
                 }
				draw_colors.push(chart.indicator_colors[0].clone());
				draw_colors.push(chart.indicator_colors[1].clone());
				draw_colors.push(chart.indicator_colors[2].clone());
				draw_colors.push(chart.indicator_colors[5].clone());
				draw_colors.push(chart.indicator_colors[4].clone());
				draw_colors.push(chart.indicator_colors[3].clone());
			} else if chart.main_indicator == "BOLL" {
                if chart.boll_mid.len() > 0{
				    draw_titles.push("MID ".to_string() + &to_fixed(chart.boll_mid[cross_line_index as usize], chart.candle_digit));
                }else{
                    draw_titles.push("MID".to_string());
                }
                if chart.boll_up.len() > 0{
				    draw_titles.push("UP ".to_string() + &to_fixed(chart.boll_up[cross_line_index as usize], chart.candle_digit));
                }else{
                    draw_titles.push("UP".to_string());
                }
                if chart.boll_down.len() > 0 {
				    draw_titles.push("LOW ".to_string() + &to_fixed(chart.boll_down[cross_line_index as usize], chart.candle_digit));
                }else{
                    draw_titles.push("LOW".to_string());
                }
				draw_colors.push(chart.indicator_colors[0].clone());
				draw_colors.push(chart.indicator_colors[1].clone());
				draw_colors.push(chart.indicator_colors[2].clone());
			}
			let mut i_left = chart.left_vscale_width + 5.0;
			for i in 0..draw_titles.len(){
				let t_size = M_PAINT.lock().unwrap().text_size(&context, draw_titles[i].clone(), chart.font.clone());
				M_PAINT.lock().unwrap().draw_text(&context, draw_titles[i].clone(), draw_colors[i].clone(), chart.font.clone(), i_left, 5.0);
				i_left = i_left + t_size.cx + 5.0;
			}
		}
		if ind_div_height > 0.0{
			let mut draw_titles = Vec::new();
			let mut draw_colors = Vec::new();
			if chart.show_indicator == "MACD" {
                if chart.alldifarr.len() > 0{
				    draw_titles.push("DIF ".to_string() + &to_fixed(chart.alldifarr[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("DIF".to_string());
                }
                if chart.alldeaarr.len() > 0{
				    draw_titles.push("DEA ".to_string() + &to_fixed(chart.alldeaarr[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("DEA".to_string());
                }
                if chart.allmacdarr.len() > 0{
				    draw_titles.push("MACD ".to_string() + &to_fixed(chart.allmacdarr[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("MACD".to_string());
                }
				draw_colors.push(chart.indicator_colors[0].clone());
				draw_colors.push(chart.indicator_colors[1].clone());
				draw_colors.push(chart.indicator_colors[4].clone());
			}else if chart.show_indicator == "KDJ" {
                if chart.kdj_k.len() > 0{
				    draw_titles.push("K ".to_string() + &to_fixed(chart.kdj_k[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("K".to_string());
                }
                if chart.kdj_d.len() > 0{
				    draw_titles.push("D ".to_string() + &to_fixed(chart.kdj_d[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("D".to_string());
                }
                if chart.kdj_j.len() > 0{
				    draw_titles.push("J ".to_string() + &to_fixed(chart.kdj_j[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("J".to_string());
                }
				draw_colors.push(chart.indicator_colors[0].clone());
				draw_colors.push(chart.indicator_colors[1].clone());
				draw_colors.push(chart.indicator_colors[2].clone());
			}else if chart.show_indicator == "RSI" {
                if chart.rsi1.len() > 0{
				    draw_titles.push("RSI6 ".to_string() + &to_fixed(chart.rsi1[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("RSI6".to_string());
                }
                if chart.rsi2.len() > 0{
				    draw_titles.push("RSI12 ".to_string() + &to_fixed(chart.rsi2[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("RSI12".to_string());
                }
                if chart.rsi3.len() > 0{
				    draw_titles.push("RSI24 ".to_string() + &to_fixed(chart.rsi3[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("RSI24".to_string());
                }
				draw_colors.push(chart.indicator_colors[5].clone());
				draw_colors.push(chart.indicator_colors[1].clone());
				draw_colors.push(chart.indicator_colors[2].clone());
			}
			else if chart.show_indicator == "BIAS" {
                if chart.bias1.len() > 0{
				    draw_titles.push("BIAS6 ".to_string() + &to_fixed(chart.bias1[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("BIAS6".to_string());
                }
                if chart.bias2.len() > 0{
				    draw_titles.push("BIAS12 ".to_string() + &to_fixed(chart.bias2[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("BIAS12".to_string());
                }
                if chart.bias3.len() > 0{
				    draw_titles.push("BIAS24 ".to_string() + &to_fixed(chart.bias3[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("BIAS24".to_string());
                }
				draw_colors.push(chart.indicator_colors[5].clone());
				draw_colors.push(chart.indicator_colors[1].clone());
				draw_colors.push(chart.indicator_colors[2].clone());
			}
			else if chart.show_indicator == "ROC" {
                if chart.roc.len() > 0{
				    draw_titles.push("ROC ".to_string() + &to_fixed(chart.roc[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("ROC".to_string());
                }
                if chart.roc_ma.len() > 0{
				    draw_titles.push("ROCMA ".to_string() + &to_fixed(chart.roc_ma[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("ROCMA".to_string());
                }
				draw_colors.push(chart.indicator_colors[0].clone());
				draw_colors.push(chart.indicator_colors[1].clone());
			}else if chart.show_indicator == "WR" {
                if chart.wr1.len() > 0{
				    draw_titles.push("WR5 ".to_string() + &to_fixed(chart.wr1[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("WR5".to_string());
                }
                if chart.wr2.len() > 0{
				    draw_titles.push("WR10 ".to_string() + &to_fixed(chart.wr2[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("WR10".to_string());
                }
				draw_colors.push(chart.indicator_colors[0].clone());
				draw_colors.push(chart.indicator_colors[1].clone());
			}else if chart.show_indicator == "CCI" {
                if chart.cci.len() > 0{
				    draw_titles.push("CCI ".to_string() + &to_fixed(chart.cci[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("CCI".to_string());
                }
				draw_colors.push(chart.indicator_colors[0].clone());
			}else if chart.show_indicator == "BBI" {
                if chart.bbi.len() > 0{
				    draw_titles.push("BBI ".to_string() + &to_fixed(chart.bbi[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("BBI".to_string());
                }
				draw_colors.push(chart.indicator_colors[0].clone());
			}else if chart.show_indicator == "TRIX" {
                if chart.trix.len() > 0{
				    draw_titles.push("TRIX ".to_string() + &to_fixed(chart.trix[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("TRIX".to_string());
                }
                if chart.trix_ma.len() > 0{
				    draw_titles.push("TRIXMA ".to_string() + &to_fixed(chart.trix_ma[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("TRIXMA".to_string());
                }
				draw_colors.push(chart.indicator_colors[0].clone());
				draw_colors.push(chart.indicator_colors[1].clone());
			}else if chart.show_indicator == "DMA" {
                if chart.dma1.len() > 0{
				    draw_titles.push("MA10 ".to_string() + &to_fixed(chart.dma1[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("MA10".to_string());
                }
                if chart.dma2.len() > 0{
				    draw_titles.push("MA50 ".to_string() + &to_fixed(chart.dma2[cross_line_index as usize], chart.ind_digit));
                }else{
                    draw_titles.push("MA50".to_string());
                }
				draw_colors.push(chart.indicator_colors[0].clone());
				draw_colors.push(chart.indicator_colors[1].clone());
			}
			let mut i_left = chart.left_vscale_width + 5.0;
			for i in 0..draw_titles.len(){
				let t_size = M_PAINT.lock().unwrap().text_size(&context, draw_titles[i].clone(), chart.font.clone());
				M_PAINT.lock().unwrap().draw_text(&context, draw_titles[i].clone(), draw_colors[i].clone(), chart.font.clone(), i_left, candle_div_height + vol_div_height + 5.0);
				i_left = i_left + t_size.cx + 5.0;
			}
		}
		if chart.show_cross_line{
			let mut right_text = String::from("");
			if chart.touch_position.y < candle_div_height {
				right_text = to_fixed(get_chart_value(chart, chart.touch_position.clone()), chart.candle_digit);
			}
			else if chart.touch_position.y > candle_div_height && chart.touch_position.y < candle_div_height + vol_div_height {
				right_text = to_fixed(get_chart_value(chart, chart.touch_position.clone()), chart.vol_digit);
			}else if chart.touch_position.y > candle_div_height + vol_div_height && chart.touch_position.y < candle_div_height + vol_div_height + ind_div_height{
				right_text = to_fixed(get_chart_value(chart, chart.touch_position.clone()), chart.ind_digit);
			}

			let mut draw_y = chart.touch_position.y;
			if draw_y > chart.view.size.cy - chart.hscale_height{
				draw_y = chart.view.size.cy - chart.hscale_height;
			}
			let t_size = M_PAINT.lock().unwrap().text_size(&context, right_text.clone(), chart.font.clone());
			if chart.left_vscale_width > 0.0{
				M_PAINT.lock().unwrap().fill_rect(&context, chart.cross_tip_color.clone(), chart.left_vscale_width - t_size.cx, draw_y - t_size.cy / 2.0 - 4.0, chart.left_vscale_width, draw_y + t_size.cy / 2.0 + 3.0);
				M_PAINT.lock().unwrap().draw_text(&context, right_text.clone(), chart.text_color.clone(), chart.font.clone(), chart.left_vscale_width - t_size.cx, draw_y - t_size.cy / 2.0);
			}
			if chart.right_vscale_width > 0.0{
				M_PAINT.lock().unwrap().fill_rect(&context, chart.cross_tip_color.clone(), chart.view.size.cx - chart.right_vscale_width, draw_y - t_size.cy / 2.0 - 4.0, chart.view.size.cx - chart.right_vscale_width + t_size.cx, draw_y + t_size.cy / 2.0 + 3.0);
				M_PAINT.lock().unwrap().draw_text(&context, right_text.clone(), chart.text_color.clone(), chart.font.clone(), chart.view.size.cx - chart.right_vscale_width, draw_y - t_size.cy / 2.0);
			}
			let mut draw_x = chart.touch_position.x;
			if draw_x < chart.left_vscale_width{
				draw_x = chart.left_vscale_width;
			}
			if draw_x > chart.view.size.cx - chart.right_vscale_width{
				draw_x = chart.view.size.cx - chart.right_vscale_width;
			}
			M_PAINT.lock().unwrap().draw_line(&context, chart.cross_line_color.clone(), chart.line_width, Vec::new(), chart.left_vscale_width, draw_y, chart.view.size.cx - chart.right_vscale_width, draw_y);
			M_PAINT.lock().unwrap().draw_line(&context, chart.cross_line_color.clone(), chart.line_width, Vec::new(), draw_x, 0.0, draw_x, chart.view.size.cy - chart.hscale_height);
	        
			if chart.cross_stop_index != -1{
				let x_text = chart.data[chart.cross_stop_index as usize].date.to_string();
				let x_size = M_PAINT.lock().unwrap().text_size(&context, x_text.clone(), chart.font.clone());
				M_PAINT.lock().unwrap().fill_rect(&context, chart.cross_tip_color.clone(), draw_x - x_size.cx / 2.0 - 2.0, candle_div_height + vol_div_height + ind_div_height, draw_x + x_size.cx / 2.0 + 2.0, candle_div_height + vol_div_height + ind_div_height + x_size.cy + 6.0);
				M_PAINT.lock().unwrap().draw_text(&context, x_text.clone(), chart.text_color.clone(), chart.font.clone(), draw_x - x_size.cx / 2.0, candle_div_height + vol_div_height + ind_div_height + 3.0);
			}
		}
     }
}

/*
* Draw chart
* context:Drawing context
* chart:Chart
* clip_rect:Crop area
*/
pub fn draw_chart(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, chart:&mut FCChart, clip_rect:FCRect){
	draw_chart_scale(&context, chart, clip_rect.clone());
	draw_chart_stock(&context, chart, clip_rect.clone());
	draw_chart_plot(&context, chart);
	draw_chart_cross_line(&context, chart, clip_rect.clone());
}

/*
* Touch move method for chart
* chart: Chart
* first_touch:Is it first touch
* first_point:Point of first touch
* second_touch:Is it second touch
* second_point:Point of second touch
*/
pub fn touch_down_chart(chart:&mut FCChart, first_touch:bool, first_point:FCPoint, second_touch:bool, second_point:FCPoint){
	chart.touch_position = first_point.clone();
	chart.touch_down_position = first_point.clone();
	chart.cross_stop_index = get_chart_index(chart, first_point.clone());
	unsafe{
		if M_ADDING_PLOT != -1{
			if first_point.y < get_candle_div_height(chart){
				let touch_index = get_chart_index(chart, first_point.clone());
				if touch_index >= chart.first_visible_index && touch_index <= chart.last_visible_index{
					let mut plots:Vec<String> = Vec::new();
					plots.push("Line".to_string());
					plots.push("Segment".to_string());
					plots.push("Ray".to_string());
					plots.push("Triangle".to_string());
					plots.push("Rect".to_string());
					plots.push("Cycle".to_string());
					plots.push("CircumCycle".to_string());
					plots.push("Ellipse".to_string());
					plots.push("AngleLine".to_string());
					plots.push("ParalleGram".to_string());
					plots.push("SpeedResist".to_string());
					plots.push("FiboFanline".to_string());
					plots.push("FiboTimezone".to_string());
					plots.push("Percent".to_string());
					plots.push("BoxLine".to_string());
					plots.push("TironeLevels".to_string());
					plots.push("Parallel".to_string());
					plots.push("GoldenRatio".to_string());
					plots.push("LRLine".to_string());
					plots.push("LRChannel".to_string());
					plots.push("LRBand".to_string());
								
					let str_plot = plots[M_ADDING_PLOT as usize].clone();
					if str_plot == "FiboTimezone"{
						let f_index = touch_index;
						let f_date = get_chart_date_by_index(chart, f_index);
						let y = get_candle_div_value(chart, first_point.clone());
						let mut new_plot:FCPlot = FCPlot::new();
						new_plot.vid = create_new_id();
						if M_PAINT.lock().unwrap().default_ui_style == "light"{
							new_plot.line_color = "rgb(0,0,0)".to_string();
							new_plot.point_color = "rgba(0,0,0,0.5)".to_string();
						}
						new_plot.key1 = f_date;
						new_plot.value1 = y;
						new_plot.plot_type = str_plot;
						chart.plots.push(new_plot);
						chart.splot = select_plot(chart, first_point.clone());
					}
					else if str_plot == "Triangle" || str_plot == "CircumCycle" || str_plot == "ParalleGram" || str_plot == "AngleLine" || str_plot == "Parallel" || str_plot == "SymmetricTriangle"{
						let e_index = touch_index;
						let b_index = e_index - 5;
						if b_index >= 0 {
							let f_date = get_chart_date_by_index(chart, b_index);
							let s_date = get_chart_date_by_index(chart, e_index);
							let y = get_candle_div_value(chart, first_point.clone());
							let mut new_plot:FCPlot = FCPlot::new();
							new_plot.vid = create_new_id();
							if M_PAINT.lock().unwrap().default_ui_style == "light"{
								new_plot.line_color = "rgb(0,0,0)".to_string();
								new_plot.point_color = "rgba(0,0,0,0.5)".to_string();
							}
							new_plot.key1 = f_date;
							new_plot.value1 = y;
							new_plot.key2 = s_date;
							new_plot.value2 = y;
							new_plot.key3 = s_date;
							new_plot.value3 = chart.candle_min + (chart.candle_max - chart.candle_min) / 2.0;
							new_plot.plot_type = str_plot;
							chart.plots.push(new_plot);
							chart.splot = select_plot(chart, first_point.clone());
						}
					}else{
						let e_index = touch_index;
						let b_index = e_index - 5;
						if b_index >= 0 {
							let f_date = get_chart_date_by_index(chart, b_index);
							let s_date = get_chart_date_by_index(chart, e_index);
							let y = get_candle_div_value(chart, first_point.clone());
							let mut new_plot:FCPlot = FCPlot::new();
							new_plot.vid = create_new_id();
							if M_PAINT.lock().unwrap().default_ui_style == "light"{
								new_plot.line_color = "rgb(0,0,0)".to_string();
								new_plot.point_color = "rgba(0,0,0,0.5)".to_string();
							}
							new_plot.key1 = f_date;
							new_plot.value1 = y;
							new_plot.key2 = s_date;
							new_plot.value2 = y;
							new_plot.plot_type = str_plot;
							chart.plots.push(new_plot);
							chart.splot = select_plot(chart, first_point.clone());
						}
					}
				}
			}
			M_ADDING_PLOT = -1;
		}else{
			chart.splot = select_plot(chart, first_point.clone());
			if chart.splot.vid <= 0{
				select_shape(chart, first_point.clone());
			}
			if M_IS_DOUBLECLICK{
				chart.show_cross_line = !chart.show_cross_line;
			}
		}
	}
	M_VIEW_MAP.lock().unwrap().insert(chart.view.view_id, chart.view.clone());
}

/*
* Default paint method
* context:Drawing context
* view:View
* clip_rect:Crop area
*/
pub fn on_paint_default(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, view:FCView, clip_rect:FCRect){
	if view.view_type == "chart"{
		M_PAINT.lock().unwrap().fill_rect(&context, view.back_color.clone(), 0.0, 0.0, view.size.cx, view.size.cy);
		for (_vid, v) in M_CHART_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				draw_chart(&context, &mut *v, clip_rect.clone());
				break;
			}
		}
	}else if view.view_type == "grid"{
		M_PAINT.lock().unwrap().fill_rect(&context, view.back_color.clone(), 0.0, 0.0, view.size.cx, view.size.cy);
		for (_vid, v) in M_GRID_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				draw_grid(&context, &mut *v, clip_rect.clone());
				break;
			}
		}		
	}
	else if view.view_type == "radiobutton"{
		for (_vid, v) in M_RADIO_BUTTON_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				draw_radio_button(&context, &mut *v, clip_rect.clone());
				break;
			}
		}		
	}
	else if view.view_type == "checkbox"{
		for (_vid, v) in M_CHECK_BOX_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				draw_check_box(&context, &mut *v, clip_rect.clone());
				break;
			}
		}	
	}
	else if view.view_type == "tab" || view.view_type == "tabpage" || view.view_type == "layout" || view.view_type == "div"{
		let mut cview = view.clone();
		draw_div(&context, &mut cview, clip_rect.clone());
	}
	else if view.view_type == "label"{
		if view.text_color != "none"{
			let t_size = M_PAINT.lock().unwrap().text_size(&context, view.text.clone(), view.font.clone());
			M_PAINT.lock().unwrap().draw_text(&context, view.text.clone(), view.text_color.clone(), view.font.clone(), 1.0, view.size.cy / 2.0 - t_size.cy / 2.0);
		}
	}
	else if view.view_type == "textbox"{
		let mut cview = view.clone();
		draw_div(&context, &mut cview, clip_rect.clone());
		if view.text_color != "none"{
			let t_size = M_PAINT.lock().unwrap().text_size(&context, view.text.clone(), view.font.clone());
			M_PAINT.lock().unwrap().draw_text(&context, view.text.clone(), view.text_color.clone(), view.font.clone(), 1.0, view.size.cy / 2.0 - t_size.cy / 2.0);
		}
	}
	else{
		let mut cview = view.clone();
		draw_button(&context, &mut cview, clip_rect.clone());
	}
}

/*
* Default paint border method
* context:Drawing context
* view:View
* clip_rect:Crop area
*/
pub fn on_paint_border_default(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, view:FCView, clip_rect:FCRect){
	if view.view_type == "grid"{
		M_PAINT.lock().unwrap().draw_rect(&context, view.border_color.clone(), 1.0, Vec::new(), 0.0, 0.0, view.size.cx, view.size.cy);
		for (_vid, v) in M_GRID_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				draw_grid_scroll_bar(&context, &mut *v, clip_rect.clone());
				break;
			}
		}
		
	}else if view.view_type == "div" || view.view_type == "layout"{
		let mut div = view.clone();
		let old_hscroll_visible = div.hscroll_is_visible;
		let old_vscroll_visible = div.vscroll_is_visible;
		draw_div_scroll_bar(&context, &mut div, clip_rect.clone());
		draw_div_border(&context, &mut div, clip_rect.clone());
		if old_hscroll_visible != div.hscroll_is_visible || old_vscroll_visible != div.vscroll_is_visible{
			M_VIEW_MAP.lock().unwrap().insert(div.view_id, div.clone());
		}
	}else if view.view_type == "tab" || view.view_type == "tabpage"{
		let mut cview = view.clone();
		draw_div_border(&context, &mut cview, clip_rect.clone());
	}else if view.view_type == "textbox"{
		let mut cview = view.clone();
		draw_div_border(&context, &mut cview, clip_rect.clone());
	}
}

/*
* Default mouse down method
* context:Drawing context
* view:View
* mp:Coordinate
* buttons:Buttons
* clicks:Click count
* delta:Delta
*/
pub fn on_mouse_down_default(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, view:FCView, mp:FCPoint, buttons:i32, clicks:i32, delta:i32){
	let mut first_touch:bool = false;
	let mut second_touch:bool = false;
	let first_point = mp.clone();
	let second_point = mp.clone();
	if buttons == 1{
		first_touch = true;
	}else if buttons == 2{
		second_touch = true;
	}
	if view.view_type == "grid"{
		for (_vid, v) in M_GRID_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				touch_down_grid(&mut *v, first_touch, first_point.clone(), second_touch, second_point.clone());
				M_VIEW_MAP.lock().unwrap().insert((*v).view.view_id, (*v).view.clone());
				break;
			}
		}
		invalidate_view(context, view.clone());
	}
	else if view.view_type == "div" || view.view_type == "layout"{
		let mut div = view.clone();
		touch_down_div(&mut div, first_touch, first_point, second_touch, second_point);
		M_VIEW_MAP.lock().unwrap().insert(div.view_id, div.clone());
		invalidate_view(context, view.clone());
	}else if view.view_type == "chart"{
		for (_vid, v) in M_CHART_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				touch_down_chart(&mut *v, first_touch, first_point, second_touch, second_point);
				break;
			}
		}
		invalidate_view(context, view.clone());
    }else if view.view_type == "button"{
		invalidate_view(context, view.clone());
	}
}

/*
* Default mouse move method
* context:Drawing context
* view:View
* mp:Coordinate
* buttons:Buttons
* clicks:Click count
* delta:Delta
*/
pub fn on_mouse_move_default(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, view:FCView, mp:FCPoint, buttons:i32, clicks:i32, delta:i32){
	let mut first_touch:bool = false;
	let mut second_touch:bool = false;
	let first_point = mp.clone();
	let second_point = mp.clone();
	if buttons == 1{
		first_touch = true;
	}else if buttons == 2{
		second_touch = true;
	}
	if view.view_type == "chart"{
		for (_vid, v) in M_CHART_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				(*v).touch_position = mp.clone();
				(*v).cross_stop_index = get_chart_index(&mut *v, mp.clone());
				touch_move_chart(&mut (*v), first_touch, first_point.clone(), second_touch, second_point.clone());
				M_VIEW_MAP.lock().unwrap().insert((*v).view.view_id, (*v).view.clone());
				break;
			}
		}
		invalidate_view(context, view.clone());
    }else if view.view_type == "grid"{
		for (_vid, v) in M_GRID_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				touch_move_grid(&mut *v, first_touch, first_point.clone(), second_touch, second_point.clone());
				M_VIEW_MAP.lock().unwrap().insert((*v).view.view_id, (*v).view.clone());
				break;
			}
		}
		if buttons == 1{
			invalidate_view(context, view.clone());
		}
	}
	else if view.view_type == "div" || view.view_type == "layout"{
		let mut div = view.clone();
		touch_move_div(&mut div, first_touch, first_point, second_touch, second_point);
		M_VIEW_MAP.lock().unwrap().insert(div.view_id, div.clone());
		if buttons == 1{
			invalidate_view(context, view.clone());
		}
	}else if view.view_type == "button"{
		invalidate_view(context, view.clone());
	}
}

/*
* Default mouse up method
* context:Drawing context
* view:View
* mp:Coordinate
* buttons:Buttons
* clicks:Click count
* delta:Delta
*/
pub fn on_mouse_up_default(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, view:FCView, mp:FCPoint, buttons:i32, clicks:i32, delta:i32){
	let mut first_touch:bool = false;
	let mut second_touch:bool = false;
	let first_point = mp.clone();
	let second_point = mp.clone();
	if buttons == 1{
		first_touch = true;
	}else if buttons == 2{
		second_touch = true;
	}
	if view.view_type == "chart"{
		for (_vid, v) in M_CHART_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				(*v).first_touch_index_cache = -1;
				(*v).second_touch_index_cache = -1;
				M_VIEW_MAP.lock().unwrap().insert((*v).view.view_id, (*v).view.clone());
				break;
			}
		}
    }else if view.view_type == "grid"{
		for (_vid, v) in M_GRID_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				touch_up_grid(&mut *v, first_touch, first_point.clone(), second_touch, second_point.clone());
				M_VIEW_MAP.lock().unwrap().insert((*v).view.view_id, (*v).view.clone());
				break;
			}
		}
		invalidate_view(context, view.clone());
	}else if view.view_type == "div" || view.view_type == "layout"{
		let mut div = view.clone();
		touch_up_div(&mut div, first_touch, first_point, second_touch, second_point);
		M_VIEW_MAP.lock().unwrap().insert(div.view_id, div.clone());
	}
	invalidate_view(context, view.clone());
}

/*
* Default click method
* context:Drawing context
* view:View
* first_touch:Coordinate
* first_point:Buttons
* second_touch:Click count
* second_point:Delta
*/
pub fn on_click_default(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, view:FCView, first_touch:bool, first_point:FCPoint, second_touch:bool, second_point:FCPoint, clicks:i32){
	if view.view_type == "checkbox"{
		for (_vid, v) in M_CHECK_BOX_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				click_check_box(&mut *v, first_point.clone());
				break;
			}
		}
		invalidate_view(context, view.clone());
	}else if view.view_type == "radiobutton"{
		for (_vid, v) in M_RADIO_BUTTON_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				click_radio_button(&mut *v, first_point.clone());
				break;
			}
		}
		invalidate_view(context, view.clone());
	}
	else if view.view_type == "headerbutton"{
		let mut is_this_tab:bool = false;
		for (_vid, v) in M_TAB_MAP.lock().unwrap().iter_mut(){
			for i in 0..(*v).tab_pages.len(){
				if (*v).tab_pages[i].header_button.view_id == view.view_id{
					is_this_tab = true;
					break;
				}
			}
			if is_this_tab{
				for j in 0..(*v).tab_pages.len(){
					if (*v).tab_pages[j].header_button.view_id == view.view_id{
						(*v).tab_pages[j].view.visible = true;
					}else{
						(*v).tab_pages[j].view.visible = false;
					}
				}
				update_tab_layout(&mut *v);
				invalidate_view(context, (*v).view.clone());
				break;
			}
		}
	}
}

/*
* Default mouse wheel method
* context:Drawing context
* view:View
* mp:Coordinate
* buttons:Buttons
* clicks:Click count
* delta:Delta
*/
pub fn on_mouse_wheel_default(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, view:FCView, mp:FCPoint, buttons:i32, clicks:i32, delta:i32){
	if view.view_type == "chart"{
		for (_vid, v) in M_CHART_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				if delta > 0{
					zoomout_chart(&mut *v);
				}else if delta < 0{
					zoomin_chart(&mut *v);
				}
				M_VIEW_MAP.lock().unwrap().insert((*v).view.view_id, (*v).view.clone());
				break;
			}
		}
		invalidate_view(context, view.clone());
    }else if view.view_type == "grid"{
		for (_vid, v) in M_GRID_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				touch_wheel_grid(&mut *v, delta);
				M_VIEW_MAP.lock().unwrap().insert((*v).view.view_id, (*v).view.clone());
				break;
			}
		}
		invalidate_view(context, view.clone());
    }
    else if view.view_type == "div" || view.view_type == "layout"{
		let mut div = view.clone();
		touch_wheel_div(&mut div, delta);
		M_VIEW_MAP.lock().unwrap().insert(div.view_id, div.clone());
		invalidate_view(context, view.clone());
    }
}

/*
* Default touch start method
* context:Drawing context
* view:View
* first_touch:Coordinate
* first_point:Buttons
* second_touch:Click count
* second_point:Delta
*/
pub fn on_touch_start_default(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, view:FCView, first_touch:bool, first_point:FCPoint, second_touch:bool, second_point:FCPoint){
	if view.view_type == "grid"{
		for (_vid, v) in M_GRID_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				touch_down_grid(&mut *v, first_touch, first_point.clone(), second_touch, second_point.clone());
				M_VIEW_MAP.lock().unwrap().insert((*v).view.view_id, (*v).view.clone());
				break;
			}
		}
		invalidate_view(context, view.clone());
	}
	else if view.view_type == "div" || view.view_type == "layout"{
		let mut div = view.clone();
		touch_down_div(&mut div, first_touch, first_point.clone(), second_touch, second_point.clone());
		M_VIEW_MAP.lock().unwrap().insert(div.view_id, div.clone());
		invalidate_view(context, view.clone());
	}else if view.view_type == "chart"{
		for (_vid, v) in M_CHART_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				touch_down_chart(&mut *v, first_touch, first_point.clone(), second_touch, second_point.clone());
				break;
			}
		}
		invalidate_view(context, view.clone());
    }else{
		invalidate_view(context, view.clone());
	}
}

/*
* Default touch move method
* context:Drawing context
* view:View
* first_touch:Coordinate
* first_point:Buttons
* second_touch:Click count
* second_point:Delta
*/
pub fn on_touch_move_default(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, view:FCView, first_touch:bool, first_point:FCPoint, second_touch:bool, second_point:FCPoint){
	if view.view_type == "chart"{
		for (_vid, v) in M_CHART_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				(*v).touch_position = first_point.clone();
				(*v).cross_stop_index = get_chart_index(&mut *v, first_point.clone());
				touch_move_chart(&mut *v, first_touch, first_point.clone(), second_touch, second_point.clone());
				M_VIEW_MAP.lock().unwrap().insert((*v).view.view_id, (*v).view.clone());
				break;
			}
		}
		invalidate_view(context, view.clone());
    }else if view.view_type == "grid"{
		for (_vid, v) in M_GRID_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				touch_move_grid(&mut *v, first_touch, first_point.clone(), second_touch, second_point.clone());
				M_VIEW_MAP.lock().unwrap().insert((*v).view.view_id, (*v).view.clone());
				break;
			}
		}
		invalidate_view(context, view.clone());
	}
	else if view.view_type == "div" || view.view_type == "layout"{
		let mut div = view.clone();
		touch_move_div(&mut div, first_touch, first_point.clone(), second_touch, second_point.clone());
		M_VIEW_MAP.lock().unwrap().insert(div.view_id, div.clone());
		invalidate_view(context, view.clone());
	}
}

/*
* Default touch end method
* context:Drawing context
* view:View
* first_touch:Coordinate
* first_point:Buttons
* second_touch:Click count
* second_point:Delta
*/
pub fn on_touch_end_default(context:&std::rc::Rc<web_sys::CanvasRenderingContext2d>, view:FCView, first_touch:bool, first_point:FCPoint, second_touch:bool, second_point:FCPoint){
	if view.view_type == "chart"{
		for (_vid, v) in M_CHART_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				(*v).first_touch_index_cache = -1;
				(*v).second_touch_index_cache = -1;
				M_VIEW_MAP.lock().unwrap().insert((*v).view.view_id, (*v).view.clone());
				break;
			}
		}
    }else if view.view_type == "grid"{
		for (_vid, v) in M_GRID_MAP.lock().unwrap().iter_mut(){
			if view.view_id == *_vid{
				(*v).view = view.clone();
				touch_up_grid(&mut *v, first_touch, first_point.clone(), second_touch, second_point.clone());
				M_VIEW_MAP.lock().unwrap().insert((*v).view.view_id, (*v).view.clone());
				break;
			}
		}
	}else if view.view_type == "div" || view.view_type == "layout"{
		let mut div = view.clone();
		touch_up_div(&mut div, first_touch, first_point.clone(), second_touch, second_point.clone());
		M_VIEW_MAP.lock().unwrap().insert(div.view_id, div.clone());
	}
	invalidate_view(context, view.clone());
}

/*
* Read xml
* element:Element
* parent:Parent view
*/
pub fn read_xml_node_default(element:&std::rc::Rc<web_sys::Element>, parent:&mut FCView){
	let node_name = element.node_name().to_lowercase();
	let mut view = FCView::new();
	if M_PAINT.lock().unwrap().default_ui_style == "dark"{
		view.back_color = "rgb(0,0,0)".to_string();
        view.border_color = "rgb(100,100,100)".to_string();
        view.text_color = "rgb(255,255,255)".to_string();
	}else if M_PAINT.lock().unwrap().default_ui_style == "light"{
		view.back_color = "rgb(255,255,255)".to_string();
        view.border_color = "rgb(150,150,150)".to_string();
        view.text_color = "rgb(0,0,0)".to_string();
	}
	if parent.view_id == -1{
		view.view_id = add_view(view.clone());
	}else{
		view.view_id = add_view_to_parent(view.clone(), parent.clone());
	}
	let node_value = element.node_value();
	let node_attributes = element.attributes();
	let mut is_div:bool = false;
	for i in 0..node_attributes.length(){
		let attribute = node_attributes.item(i).expect("REASON");
		let atr_name = attribute.name().to_lowercase();
		let atr_value = attribute.value();
		set_view_attribute_default(&mut view, atr_name.clone(), atr_value.clone());
		if node_name == "div" || node_name == "view"{
			if atr_name == "type"{
				if atr_value == "splitlayout"{
					view.view_type = "split".to_string();
				}
				else if atr_value == "layout"{
					view.view_type = "layout".to_string();
					view.show_vscrollbar = true;
					view.show_hscrollbar = true;
					view.allow_drag_scroll = true;
				}
				else if atr_value == "tab"{
					view.view_type = "tabview".to_string();
				}
				else if atr_value == "tabpage"{
					view.view_type = "tabpage".to_string();
				}
				else if atr_value == "radio"{
					view.view_type = "radiobutton".to_string();
				}else if atr_value == "checkbox"{
					view.view_type = "checkbox".to_string();
				}else if atr_value == "button"{
					view.view_type = "button".to_string();
				}else{
					is_div = true;
				}
			}
		}else if node_name == "input"{
			if atr_name == "type"{
				if atr_value == "radio"{
					view.view_type = "radiobutton".to_string();
				}else if atr_value == "checkbox"{
					view.view_type = "checkbox".to_string();
				}else if atr_value == "button"{
					view.view_type = "button".to_string();
				}else if atr_value == "range" || atr_value == "text"{
					view.view_type = "textbox".to_string();
				}else{
					is_div = true;
				}
			}
		}
	}
	if node_name == "chart"{
		view.view_type = "chart".to_string();
	}else if node_name == "label"{
		view.view_type = "label".to_string();
	}else if node_name == "table"{
		view.view_type = "grid".to_string();
		view.show_vscrollbar = true;
		view.show_hscrollbar = true;
		view.allow_drag_scroll = true;
	}else if is_div{
		view.view_type = "div".to_string();
		view.show_vscrollbar = true;
		view.show_hscrollbar = true;
		view.allow_drag_scroll = true;
	}
	M_VIEW_MAP.lock().unwrap().insert(view.view_id, view.clone());
	if view.view_type == "split"{
		let mut split:FCSplitLayoutDiv = FCSplitLayoutDiv::new();
		let mut splitterposition : String = String::from("");
		let mut can_drag_splitter : bool = false;
		for i in 0..node_attributes.length(){
			let attribute = node_attributes.item(i).expect("REASON");
			let atr_name = attribute.name().to_lowercase();
			let atr_value = attribute.value();
			set_split_attribute_default(&mut split, atr_name.clone(), atr_value.clone());
			if atr_name == "datumsize"{
				let str_split:Vec<&str> = atr_value.split(",").collect();
				let cx : f32 = str_split[0].parse::<f32>().unwrap();
				let cy : f32 =  str_split[1].parse::<f32>().unwrap();
				view.size = FCSize{cx:cx, cy:cy};	
			}else if atr_name == "splitterposition"{
				splitterposition = atr_value;
			}else if atr_name == "candragsplitter"{
				if atr_value == "true"{
					can_drag_splitter = true;
				}
			}
		}
		M_VIEW_MAP.lock().unwrap().insert(view.view_id, view.clone());
		let mut splitter:FCView = FCView::new();
		if M_PAINT.lock().unwrap().default_ui_style == "dark"{
			splitter.back_color = "rgb(100,100,100)".to_string();
		}else if M_PAINT.lock().unwrap().default_ui_style == "light"{
			splitter.back_color = "rgb(150,150,150)".to_string();
		}
		splitter.allow_drag = can_drag_splitter;
		let str_split:Vec<&str> = splitterposition.split(",").collect();
		if str_split.len() >= 4{
			let left : f32 = str_split[0].parse::<f32>().unwrap();
			let top : f32 =  str_split[1].parse::<f32>().unwrap();
			let right : f32 = str_split[2].parse::<f32>().unwrap();
			let bottom : f32 =  str_split[3].parse::<f32>().unwrap();
			splitter.location = FCPoint{x:left, y:top};
			splitter.size = FCSize{cx:right - left + 1.0, cy:bottom - top + 1.0};
		}else{
			let s_position : f32 = str_split[0].parse::<f32>().unwrap();
			let s_size : f32 =  str_split[1].parse::<f32>().unwrap();
			if split.layout_style == "lefttoright" || split.layout_style == "righttoleft"{
                splitter.location = FCPoint{x:s_position, y:0.0};
                splitter.size = FCSize{cx:s_size, cy:view.size.cy};
            }else{
                splitter.location = FCPoint{x:0.0, y:s_position};
                splitter.size = FCSize{cx:view.size.cx, cy:s_size};
            }
		}
		let child_elements = element.children();
		for i in 0..child_elements.length(){
			let sub_node = child_elements.item(i).expect("REASON");
			let sub_node = Rc::new(sub_node);
			read_xml_node_default(&sub_node, &mut view);
		}
		let sub_views = get_sub_views(view.clone());
		let first_view = (&sub_views[0]).clone();
		let second_view = (&sub_views[1]).clone();
		if first_view.view_id >= second_view.view_id{
			split.first_view = second_view;
			split.second_view = first_view;
		}else{
			split.first_view = first_view;
			split.second_view = second_view;
		}
		splitter.view_id = add_view_to_parent(splitter.clone(), view.clone());
		split.splitter = splitter.clone();
		split.view = view.clone();
		split.old_size = view.size.clone();
		reset_split_layout_div(&mut split);
		M_SPLIT_MAP.lock().unwrap().insert(view.view_id, split.clone());
	}
	else if view.view_type == "chart"{
		let mut chart:FCChart = FCChart::new();
		chart.view = view.clone();
		M_CHART_MAP.lock().unwrap().insert(view.view_id, chart.clone());
	}
	else if view.view_type == "checkbox"{
		let mut check_box:FCCheckBox = FCCheckBox::new();
		for i in 0..node_attributes.length(){
			let attribute = node_attributes.item(i).expect("REASON");
			let atr_name = attribute.name().to_lowercase();
			let atr_value = attribute.value();
			set_check_box_attribute_default(&mut check_box, atr_name.clone(), atr_value.clone());
		}
		check_box.view = view.clone();
		M_CHECK_BOX_MAP.lock().unwrap().insert(view.view_id, check_box.clone());
	}
	else if view.view_type == "radiobutton"{
		let mut radio_button:FCRadioButton = FCRadioButton::new();
		for i in 0..node_attributes.length(){
			let attribute = node_attributes.item(i).expect("REASON");
			let atr_name = attribute.name().to_lowercase();
			let atr_value = attribute.value();
			set_radio_button_attribute_default(&mut radio_button, atr_name.clone(), atr_value.clone());
		}
		radio_button.view = view.clone();
		M_RADIO_BUTTON_MAP.lock().unwrap().insert(view.view_id, radio_button.clone());
	}
	else if view.view_type == "grid"{
		let mut grid:FCGrid = FCGrid::new();
		for i in 0..node_attributes.length(){
			let attribute = node_attributes.item(i).expect("REASON");
			let atr_name = attribute.name().to_lowercase();
			let atr_value = attribute.value();
			set_grid_attribute_default(&mut grid, atr_name.clone(), atr_value.clone());
		}
		grid.view = view.clone();
		let child_elements = element.children();
		for i in 0..child_elements.length(){
			let sub_node = child_elements.item(i).expect("REASON");
			let sub_node_name = sub_node.node_name().to_lowercase();
			if sub_node_name == "tr"{
				let sun_elements = sub_node.children();
				for j in 0..sun_elements.length(){
					let sun_node = sun_elements.item(j).expect("REASON");
					let sun_node_name = sun_node.node_name().to_lowercase();
					if sun_node_name == "th"{
						let mut grid_column:FCGridColumn = FCGridColumn::new();
						grid_column.allow_resize = true;
						if M_PAINT.lock().unwrap().default_ui_style == "dark"{
							grid_column.back_color = "rgb(0,0,0)".to_string();
							grid_column.border_color = "rgb(100,100,100)".to_string();
							grid_column.text_color = "rgb(255,255,255)".to_string();
						}else if M_PAINT.lock().unwrap().default_ui_style == "light"{
							grid_column.back_color = "rgb(255,255,255)".to_string();
							grid_column.border_color = "rgb(150,150,150)".to_string();
							grid_column.text_color = "rgb(0,0,0)".to_string();
						}
						let sun_node_attributes = sun_node.attributes();
						for k in 0..sun_node_attributes.length(){
							let sun_attr = sun_node_attributes.item(k).expect("REASON");
							let sun_atr_name = sun_attr.name().to_lowercase();
							let sun_atr_value = sun_attr.value();
							if sun_atr_name == "text"{
								grid_column.text = sun_atr_value;
								break;
							}
						}
						grid.columns.push(grid_column);
					}
				}
			}
		}
		M_GRID_MAP.lock().unwrap().insert(view.view_id, grid.clone());
	}
	else{
		if view.view_type == "layout"{
			let mut layout:FCLayoutDiv = FCLayoutDiv::new();
			for i in 0..node_attributes.length(){
				let attribute = node_attributes.item(i).expect("REASON");
				let atr_name = attribute.name().to_lowercase();
				let atr_value = attribute.value();
				set_layout_attribute_default(&mut layout, atr_name.clone(), atr_value.clone());
			}
			layout.view = view.clone();
			M_LAYOUT_MAP.lock().unwrap().insert(view.view_id, layout.clone());
		}
		else if view.view_type == "tabview"{
			let mut tab:FCTabView = FCTabView::new();
			tab.view = view.clone();
			M_TAB_MAP.lock().unwrap().insert(view.view_id, tab.clone());
		}else if view.view_type == "tabpage"{
			let mut tab = M_TAB_MAP.lock().unwrap()[&parent.view_id].clone();
			let mut header_button_view:FCView = FCView::new();
			header_button_view.size = FCSize{cx:100.0, cy:20.0};
			header_button_view.view_type = "headerbutton".to_string();
			for i in 0..node_attributes.length(){
				let attribute = node_attributes.item(i).expect("REASON");
				let atr_name = attribute.name().to_lowercase();
				let atr_value = attribute.value();
				if atr_name == "text"{
					header_button_view.text = atr_value;
				}else if atr_name == "headersize"{
					let str_split:Vec<&str> = atr_value.split(",").collect();
					let cx : f32 = str_split[0].parse::<f32>().unwrap();
					let cy : f32 =  str_split[1].parse::<f32>().unwrap();
					header_button_view.size = FCSize{cx:cx, cy:cy};
				}
			}
			if M_PAINT.lock().unwrap().default_ui_style == "dark"{
				header_button_view.back_color = "rgb(0,0,0)".to_string();
				header_button_view.border_color = "rgb(100,100,100)".to_string();
				header_button_view.text_color = "rgb(255,255,255)".to_string();
			}else if M_PAINT.lock().unwrap().default_ui_style == "light"{
				header_button_view.back_color = "rgb(255,255,255)".to_string();
				header_button_view.border_color = "rgb(150,150,150)".to_string();
				header_button_view.text_color = "rgb(0,0,0)".to_string();
			}
			header_button_view.view_id = add_view_to_parent(header_button_view.clone(), parent.clone());
			if tab.tab_pages.len() > 0{
				view.visible = false;
				M_VIEW_MAP.lock().unwrap().insert(view.view_id, view.clone());
			}
			let mut tab_page:FCTabPage = FCTabPage::new();
			tab_page.view = view.clone();
			tab_page.header_button = header_button_view.clone();
			tab.tab_pages.push(tab_page);
			M_TAB_MAP.lock().unwrap().insert(tab.view.view_id, tab.clone());
		}
		let child_elements = element.children();
		for i in 0..child_elements.length(){
			let sub_node = child_elements.item(i).expect("REASON");
			let sub_node = Rc::new(sub_node);
			read_xml_node_default(&sub_node, &mut view);
		}
	}
}

/*
* Set attribute of gird
* grid:Grid
* name:Name
* value:Value
*/
pub fn set_grid_attribute_default(grid:&mut FCGrid, name:String, value:String){
	if name == "headerheight"{
		grid.header_height = value.parse::<f32>().unwrap();
	}
}

/*
* Set attribute of check box
* check_box:Check box
* name:Name
* value:Value
*/
pub fn set_check_box_attribute_default(check_box:&mut FCCheckBox, name:String, value:String){
	if name == "checked"{
		if value == "true"{
			check_box.checked = true;
		}else{
			check_box.checked = false;
		}
	}else if name == "buttonsize"{
		let str_split:Vec<&str> = value.split(",").collect();
		let cx : f32 = str_split[0].parse::<f32>().unwrap();
		let cy : f32 =  str_split[1].parse::<f32>().unwrap();
		check_box.button_size = FCSize{cx:cx, cy:cy};
	}
}

/*
* Set attribute of radio button
* radio_button:Radio button
* name:Name
* value:Value
*/
pub fn set_radio_button_attribute_default(radio_button:&mut FCRadioButton, name:String, value:String){
	if name == "checked"{
		if value == "true"{
			radio_button.checked = true;
		}else{
			radio_button.checked = false;
		}
	}else if name == "buttonsize"{
		let str_split:Vec<&str> = value.split(",").collect();
		let cx : f32 = str_split[0].parse::<f32>().unwrap();
		let cy : f32 =  str_split[1].parse::<f32>().unwrap();
		radio_button.button_size = FCSize{cx:cx, cy:cy};
	}
}

/*
* Set attribute of SplitLayoutDiv
* split:SplitLayoutDiv
* name:Name
* value:Value
*/
pub fn set_split_attribute_default(split:&mut FCSplitLayoutDiv, name:String, value:String){
	if name == "layoutstyle"{
		split.layout_style = value.to_lowercase();
	}else if name == "splitmode"{
		split.split_mode = value.to_lowercase();
	}
}

/*
* Set attribute of LayoutDiv
* layout:LayoutDiv
* name:Name
* value:Value
*/
pub fn set_layout_attribute_default(layout:&mut FCLayoutDiv, name:String, value:String){
	if name == "layoutstyle"{
		layout.layout_style = value.to_lowercase();
	}else if name == "autowrap"{
		if value == "true"{
			layout.auto_wrap = true;
		}else{
			layout.auto_wrap = false;
		}
	}
}

/*
* Default set attribute method
* view:View
* name:Name
* value:Value
*/
pub fn set_view_attribute_default(view:&mut FCView, name:String, value:String){
	if name == "location"{
		let str_split:Vec<&str> = value.split(",").collect();
		let x : f32 = str_split[0].parse::<f32>().unwrap();
		let y : f32 =  str_split[1].parse::<f32>().unwrap();
		view.location = FCPoint{x:x, y:y};
	}
	else if name == "size"{
		let str_split:Vec<&str> = value.split(",").collect();
		let cx : f32 = str_split[0].parse::<f32>().unwrap();
		let cy : f32 =  str_split[1].parse::<f32>().unwrap();
		view.size = FCSize{cx:cx, cy:cy};
	}else if name == "text"{
		view.text = value;
	}else if name == "cursor"{
		view.cursor = value;
	}else if name == "backcolor"{ 
		if value.find("rgb") == Some(0){
			view.back_color = value;
		}else{
			view.back_color = "none".to_string();
		}
	}else if name == "bordercolor"{
		if value.find("rgb") == Some(0){
			view.border_color = value;
		}else{
			view.border_color = "none".to_string();
		}
	}else if name == "hoveredcolor"{
		if value.find("rgb") == Some(0){
			view.hovered_color = value;
		}else{
			view.hovered_color = "none".to_string();
		}
	}else if name == "cornerradius"{
		view.corner_radius = value.parse::<f32>().unwrap();
	}else if name == "borderwidth"{
		view.border_width = value.parse::<f32>().unwrap();
	}else if name == "textcolor"{
		if value.find("rgb") == Some(0){
			view.text_color = value;
		}else{
			view.text_color = "none".to_string();
		}
	}else if name == "dock"{
		view.dock = value.to_lowercase();
	}else if name == "font"{
		view.font = value;
	}else if name == "name"{
		view.view_name = value;
	}
	else if name == "enabled"{
		if value.to_lowercase() == "true"{
			view.enabled = true;
		}else{
			view.enabled = false;
		}
	}else if name == "showvscrollbar"{
		if value.to_lowercase() == "true"{
			view.show_vscrollbar = true;
		}else{
			view.show_vscrollbar = false;
		}
	}else if name == "showhscrollbar"{
		if value.to_lowercase() == "true"{
			view.show_hscrollbar = true;
		}else{
			view.show_hscrollbar = false;
		}
	}else if name == "visible"{
		if value.to_lowercase() == "true"{
			view.visible = true;
		}else{
			view.visible = false;
		}
	}else if name == "displayoffset"{
		if value.to_lowercase() == "true"{
			view.display_offset = true;
		}else{
			view.display_offset = false;
		}
	}else if name == "topmost"{
		if value.to_lowercase() == "true"{
			view.top_most = true;
		}else{
			view.top_most = false;
		}
	}else if name == "allowdrag"{
		if value.to_lowercase() == "true"{
			view.allow_drag = true;
		}else{
			view.allow_drag = false;
		}
	}else if name == "allowresize"{
		if value.to_lowercase() == "true"{
			view.allow_resize = true;
		}else{
			view.allow_resize = false;
		}
	}
}

/*
* Update Layout Status
* views:View collection
*/
pub fn update_view_default(views:Vec<FCView>){
	let views_size = views.len();
		for i in 0..views_size{
		let mut view = (&views[i]).clone();
		let mut find:bool = false;
		let mut p_id:i32 = 0;
		match M_PARENT_VIEW_MAP.lock().unwrap().get(&view.view_id) {
			Some(x) => {
				find = true;
				p_id = *x;	
			},
			None => {
				find = false;
			}
		}
		if find && view.dock == "fill"{
			let parent = M_VIEW_MAP.lock().unwrap()[&p_id].clone();
			if parent.view_type != "split"{
				view.location = FCPoint{x:0.0, y:0.0};
				view.size = FCSize{cx:parent.size.cx, cy:parent.size.cy};
			}
		}else if !find && view.dock == "fill"{
			view.location = FCPoint{x:0.0, y:0.0};
			unsafe{
				let scale_factor_x = M_PAINT.lock().unwrap().scale_factor_x;
				let scale_factor_y = M_PAINT.lock().unwrap().scale_factor_y;
				view.size = FCSize{cx:M_CANVAS_WIDTH / scale_factor_x, cy:M_CANVAS_HEIGHT / scale_factor_y};
			}
		}
		M_VIEW_MAP.lock().unwrap().insert(view.view_id, view.clone());
		if view.view_type == "split"{
			for (_vid, v) in M_SPLIT_MAP.lock().unwrap().iter_mut(){
				if view.view_id == *_vid{
					(*v).view = view.clone();
					reset_split_layout_div(&mut *v);
				}
			}
        }else if view.view_type == "tabview"{
			for (_vid, v) in M_TAB_MAP.lock().unwrap().iter_mut(){
				if view.view_id == *_vid{
					(*v).view = view.clone();
					update_tab_layout(&mut *v);
				}
			}
        }else if view.view_type == "layout"{
			for (_vid, v) in M_LAYOUT_MAP.lock().unwrap().iter_mut(){
				if view.view_id == *_vid{
					(*v).view = view.clone();
					reset_layout_div(&mut *v);
				}
			}
        }else if view.view_type == "chart"{
			for (_vid, v) in M_CHART_MAP.lock().unwrap().iter_mut(){
				if view.view_id == *_vid{
					(*v).view = view.clone();
					reset_chart_visible_record(&mut *v);
					check_chart_last_visible_index(&mut *v);
					calculate_chart_max_min(&mut *v);
				}
			}
        }
		let sub_views = get_sub_views(view.clone());
		let sub_views_size = sub_views.len();
		if sub_views_size > 0 {
			update_view_default(sub_views);
		}
	}
}

/*
* Window resize
*/
pub fn window_resize(rect:&mut FCRect, resizePoint:i32, nowPoint:FCPoint, startTouchPoint:FCPoint){
	if resizePoint == 0{
		rect.left = rect.left + nowPoint.x - startTouchPoint.x;
		rect.top = rect.top + nowPoint.y - startTouchPoint.y;
	}
	else if resizePoint == 1{
		rect.left = rect.left + nowPoint.x - startTouchPoint.x;
		rect.bottom = rect.bottom + nowPoint.y - startTouchPoint.y;
	}
	else if resizePoint == 2{
		rect.right = rect.right + nowPoint.x - startTouchPoint.x;
		rect.top = rect.top + nowPoint.y - startTouchPoint.y;
	}
	else if resizePoint == 3{
		rect.right = rect.right + nowPoint.x - startTouchPoint.x;
		rect.bottom = rect.bottom + nowPoint.y - startTouchPoint.y;
	}
	else if resizePoint == 4{
		rect.left = rect.left + nowPoint.x - startTouchPoint.x;
	}
	else if resizePoint == 5{
		rect.top = rect.top + nowPoint.y - startTouchPoint.y;
	}
	else if resizePoint == 6{
		rect.right = rect.right + nowPoint.x - startTouchPoint.x;
	}
	else if resizePoint == 7{
		rect.bottom = rect.bottom + nowPoint.y - startTouchPoint.y;
	}
}

/*
* Get resize state
*/
pub fn get_resize_state(view:FCView, mp:FCPoint)->i32{
	let bWidth = 5.0;
	let width = view.size.cx;
	let height = view.size.cy;
	if mp.x >= 0.0 && mp.x <= bWidth * 2.0 && mp.y >= 0.0 && mp.y <= bWidth * 2.0{
		return 0;
	}else if mp.x >= 0.0 && mp.x <= bWidth * 2.0 && mp.y >= height - bWidth * 2.0 && mp.y <= height{
		return 1;
	}else if mp.x >= width - bWidth * 2.0 && mp.x <= width && mp.y >= 0.0 && mp.y <= bWidth * 2.0{
		return 2;
	}else if mp.x >= width - bWidth * 2.0 && mp.x <= width && mp.y >= height - bWidth * 2.0 && mp.y <= height{
		return 3;
	}else if mp.x >= 0.0 && mp.x <= bWidth && mp.y >= 0.0 && mp.y <= height{
		return 4;
	}else if mp.x >= 0.0 && mp.x <= width && mp.y >= 0.0 && mp.y <= bWidth{
		return 5;
	}else if mp.x >= width - bWidth && mp.x <= width && mp.y >= 0.0 && mp.y <= height{
		return 6;
	}else if mp.x >= 0.0 && mp.x <= width && mp.y >= height - bWidth && mp.y <= height{
		return 7;
	}else{
		return -1;
	}
}

/*
* Render the xml
* xml: content
*/
pub fn render_facecat(xml:String){
	let dom_parse = DomParser::new();
	let s_type = SupportedType::TextXml;
	let xml_doc = dom_parse.expect("REASON").parse_from_string(&xml, s_type);
	let body = xml_doc.expect("REASON").get_elements_by_tag_name("body").item(0);
	let node_list = body.expect("REASON").children();
	let mut none_view = M_NONE_VIEW.lock().unwrap().clone();
	for i in 0..node_list.length(){
		let node = node_list.item(i).expect("REASON");
		let node = Rc::new(node);
		read_xml_node_default(&node, &mut none_view);
	}
	let top_views3 = get_top_views();
	update_view_default(top_views3);
}